文字エンコードとロケールを体感する
前回からの続き。
今時、OSX環境ならUTF-8で使っていれば何の問題もないだろう、と信じていると痛い目に遭う。
文字化けする現象
- AppleScriptエディタで、ファイルフォーマット=テキストで保存してみる。
tell application "Finder" display dialog "こんばんは" end tell
____ここから、ターミナルの環境設定 >> 設定 >> 詳細 >> 言語環境:文字エンコーディング=日本語(UTF-8)____
- 新規タブを開いて、catコマンドで確認すると...
$ cat $HOME/Library/Scripts/encoding_test.applescript
tell application "Finder"
display dialog "??????"
end tell
- 見事に文字化けしている。
正しく表示される場合
- 再び、テキストエディットを開いて標準テキストの新規書類に、まったく同じ内容を手入力してみる。
tell application "Finder" display dialog "こんばんは" end tell
- catコマンドで確認すると...
$ cat $HOME/Documents/encoding_test.txt
tell application "Finder"
display dialog "こんばんは"
end
- 文字化けせずに正常に表示された。
ダンプ表示で違いを知る
- この違いを知るには、odコマンドでダンプ(16進数コード)表示してみると、よく分かる。
____ここから、ターミナルの環境設定 >> 設定 >> 詳細 >> 言語環境:文字エンコーディング=日本語(Shift JIS)____
- その前に、ターミナルの環境設定 >> 設定 >> 詳細で、文字エンコーディング=日本語(Shift JIS)にしておく。
- ターミナルで新規タブを開いて、以下のコマンドを実行した。
$ od -tx1c $HOME/Library/Scripts/encoding_test.applescript 0000000 74 65 6c 6c 20 61 70 70 6c 69 63 61 74 69 6f 6e t e l l a p p l i c a t i o n 0000020 20 22 46 69 6e 64 65 72 22 0a 09 64 69 73 70 6c " F i n d e r " \n \t d i s p l 0000040 61 79 20 64 69 61 6c 6f 67 20 22 82 b1 82 f1 82 a y d i a l o g " こ ** ん ** ば 0000060 ce 82 f1 82 cd 22 0a 65 6e 64 20 74 65 6c 6c ** ん ** は ** " \n e n d t e l l 0000077
- ターミナルの設定により、この新規タブの言語環境はShift JISになっている。
- そして、Shift JIS環境なら、文字化けしないで表示される。
$ cat $HOME/Library/Scripts/encoding_test.applescript
tell application "Finder"
display dialog "こんばんは"
end tell
- つまり、encoding_test.applescriptは、Shift JISでエンコードされたテキストなのだ。
- Shift JISの言語環境で、Shift JISでエンコードされたテキストならば、正常に表示される。
____ここから、ターミナルの環境設定 >> 設定 >> 詳細 >> 言語環境:文字エンコーディング=日本語(UTF-8)____
- ターミナルで最初のタブに戻って、以下のコマンドを実行した。
$ od -tx1c $HOME/Documents/encoding_test.txt 0000000 74 65 6c 6c 20 61 70 70 6c 69 63 61 74 69 6f 6e t e l l a p p l i c a t i o n 0000020 20 22 46 69 6e 64 65 72 22 0a 09 64 69 73 70 6c " F i n d e r " \n \t d i s p l 0000040 61 79 20 64 69 61 6c 6f 67 20 22 e3 81 93 e3 82 a y d i a l o g " こ ** ** ん ** 0000060 93 e3 81 b0 e3 82 93 e3 81 af 22 0a 65 6e 64 ** ば ** ** ん ** ** は ** ** " \n e n d 0000077
- オレンジ色の太字がその違い。
- 「こんばんは」の部分である。
- 16進数ダンプ表示された文字コードの値も、バイト数も、まったく違っているのだ!
$ cat $HOME/Documents/encoding_test.txt
tell application "Finder"
display dialog "こんばんは"
end
言語環境と、テキストのエンコード方式は、一致させる必要があるのだ!
- 一致すれば正常に表示され、違っていると文字化けする。
ターミナルの言語環境とコマンドのロケール
- ややこしいのは、二つの言語環境があること。
- ターミナルの設定としての言語環境と、
- コマンド実行環境としてのロケール。
- ところが、今回のようにターミナルの言語環境を切り替え、ターミナルを再起動せずに使っていると、不一致な状態に陥る。
$ locale LANG="ja_JP.SJIS" LC_COLLATE="ja_JP.SJIS" LC_CTYPE="ja_JP.SJIS" LC_MESSAGES="ja_JP.SJIS" LC_MONETARY="ja_JP.SJIS" LC_NUMERIC="ja_JP.SJIS" LC_TIME="ja_JP.SJIS" LC_ALL=
- この状態だと、先ほどは正常に表示されたencoding_test.applescriptも、文字化けすることになる。
$ cat $HOME/Library/Scripts/encoding_test.applescript
tell application "Finder"
display dialog "??????"
end tell
- つまり、最終的には3つの言語環境を一致させておく必要があるのだ。
言語環境の区分 | 意味 |
---|---|
テキストファイル | ファイルに記録されているエンコード方式 |
コマンドロケール | コマンド処理する時に解釈されるエンコード方式 |
ターミナル言語環境 | 画面出力する時に解釈されるエンコード方式 |
- すべてのエンコード方式が一致した時のみ
テキストファイル | コマンドロケール | ターミナル言語環境 | 出力結果 | 判定 |
---|---|---|---|---|
Shift JIS | Shift JIS | Shift JIS | こんばんは | OK |
Shift JIS | Shift JIS | UTF-8 | ?????? | 文字化け |
Shift JIS | UTF-8 | UTF-8 | ?????? | 文字化け |
UTF-8 | UTF-8 | UTF-8 | こんばんは | OK |
UTF-8 | UTF-8 | Shift JIS | 縺薙s縺ー繧薙� | 文字化け |
UTF-8 | Shift JIS | Shift JIS | 縺薙s縺ー繧薙� | 文字化け |
ロケールの影響を受けるコマンド、受けないコマンド
- ところで、コマンドには、ロケールの影響を受けるものと、受けないものがある。
- 例えば、catコマンドはどんなロケールだろうと、忠実にテキストファイルの文字コードをそのまま読み取り、そのまま出力する。
- よって、以下のようなロケールであっても、正常に表示されるのだ。
テキストファイル | コマンドロケール | ターミナル言語環境 | 出力結果 | 判定 |
---|---|---|---|---|
Shift JIS | UTF-8 | Shift JIS | こんにちは | OK |
$ cat $HOME/Library/Scripts/encoding_test.applescript
tell application "Finder"
display dialog "こんばんは"
end tell
- ところが、odコマンドを実行すると、このようになる。
$ od -tx1c $HOME/Library/Scripts/encoding_test.applescript 0000000 74 65 6c 6c 20 61 70 70 6c 69 63 61 74 69 6f 6e t e l l a p p l i c a t i o n 0000020 20 22 46 69 6e 64 65 72 22 0a 09 64 69 73 70 6c " F i n d e r " \n \t d i s p l 0000040 61 79 20 64 69 61 6c 6f 67 20 22 82 b1 82 f1 82 a y d i a l o g " 202 261 202 316 202 0000060 ce 82 f1 82 cd 22 0a 65 6e 64 20 74 65 6c 6c 316 202 361 202 315 " \n e n d t e l l 0000077
- 「こんばんは」と表示されずに、8進数文字コードで表示されている。
- 3つすべての言語環境が一致していれば、本来は「こんばんは」と表示されるはず。
$ od -tx1c $HOME/Library/Scripts/encoding_test.applescript 0000000 74 65 6c 6c 20 61 70 70 6c 69 63 61 74 69 6f 6e t e l l a p p l i c a t i o n 0000020 20 22 46 69 6e 64 65 72 22 0a 09 64 69 73 70 6c " F i n d e r " \n \t d i s p l 0000040 61 79 20 64 69 61 6c 6f 67 20 22 82 b1 82 f1 82 a y d i a l o g " こ ** ん ** ば 0000060 ce 82 f1 82 cd 22 0a 65 6e 64 20 74 65 6c 6c ** ん ** は ** " \n e n d t e l l 0000077
ロケールの設定方法
- 今まで、ターミナルの設定で「起動時にロケール環境変数を設定=チェックあり」に頼っていた。
- でも場合によっては、ロケールのみを個別に設定したい状況もあり得る。
- また、ターミナル以外の実行環境でコマンドを実行する場合も結構ある。
- 例えばAppleScriptのdo shell scriptとか、
- Automatorのシェルスクリプトを実行するアクションなど。
- そんな時は、コマンドを使って、自分でロケールを設定し直す必要がある。
設定可能なロケール一覧
- OSがサポートするロケールを表示する。
$ locale -a
$ locale -a | grep ja_JP ja_JP ja_JP.eucJP ja_JP.SJIS ja_JP.UTF-8
ロケールを設定する
- ロケールはLANG変数に設定して、exportする必要がある。
$ export LANG=ja_JP.UTF-8 $ locale LANG="ja_JP.UTF-8" LC_COLLATE="ja_JP.UTF-8" LC_CTYPE="ja_JP.UTF-8" LC_MESSAGES="ja_JP.UTF-8" LC_MONETARY="ja_JP.UTF-8" LC_NUMERIC="ja_JP.UTF-8" LC_TIME="ja_JP.UTF-8" LC_ALL=
- LANG変数が設定されていないと、英語環境になるのだと思う。
- AppleScriptやAutomatorのコマンド実行環境は、LANG変数が未設定である。
$ unset LANG $ locale LANG= LC_COLLATE="C" LC_CTYPE="C" LC_MESSAGES="C" LC_MONETARY="C" LC_NUMERIC="C" LC_TIME="C" LC_ALL=
AppleScriptやAutomatorでテキスト処理をするなら、export LANG=ja_JP.UTF-8を設定しておくと幸せになる。
文字コードを変換する方法
- コマンド環境で文字コードを変換するには、自分は現状nkfコマンドに頼りきっている。
- nkfコマンドはOSX標準インストールされないのだけど、テキストのエンコード方式を自動判定してくれるところが、たいへん便利。
$ cat $HOME/Library/Scripts/encoding_test.applescript | nkf -w tell application "Finder" display dialog "こんばんは" end tell $ cat $HOME/Documents/encoding_test.txt | nkf -w tell application "Finder" display dialog "こんばんは" end