・「〜」の文字コード
Windowsな環境で作ったアーカイブファイルをPlamoな環境で開いた場合、ファイル名の文字コードはだいたい問題なくEUC-JPに変換されるのだけど、 たまに "〜” がおかしい場合があるので少し調べてみた。
結構イヤらしいのは、KDEのKonsoleやgnome-terminal, XfceのTerminal上だと問題なく"〜”が表示されるけど、 EmacsやFD経由だとうまく表示されない、という環境依存なところ。
例えば、この a と b というファイルは、上記問題のないターミナル上だと同じに表示される
% cat a A〜B C〜D
% cat b A〜B C〜D
ところが、Emacsで開くと、ファイル a の"〜”は正しく表示できない
何が違うんだろう、、としばらく調べてみたところ、hexdump -C で見ると文字コードが違っていることがわかった。
% hexdump -C a 00000000 41 8f a2 b7 42 0a 43 8f a2 b7 44 0a |A...B.C...D.| 0000000c % hexdump -C b 00000000 41 a1 c1 42 0a 43 a1 c1 44 0a |A..B.C..D.| 0000000a
これで見ると、ファイル b の "〜" は a1c1 という正しい euc-jp のコードになっているのに対して、 ファイル a の "〜" は、同じ "〜”に見えるものの、8f a2 b7 というコードになっているらしい。
この 8f a2 b7 というシーケンスが、なぜ "〜" になるのかはあれこれ調べてみたけどよく分からない。
8f は JIS X 0211のC1集合のss3(Single Shift 3)かな、と思うが、Shift-JIS でも EUC-JP でも UTF-8 でも a2 b7 なんてコードは無さげなのだが、Konsoleとかgnome-terminal、Terminalが同じ 結果を示しているのを見ると、何らかのルールは決まってそうな印象
識者の目に触れることを期待して、このあたりに晒しておこう :-)
% cat a A〜B C〜D % nkf -e a A召キB C召キD
この結果を見る限り、8f a2 b7 というシーケンスは nkf が認識する(= 広く一般に使われている)コードとは違っていて、 それらを素で通したらkonsole等のターミナルが"〜"にしているような印象。ktermでは対応していないようなので、gtk+とか Qtのレベルなのかなぁ?-- kojima 2010-08-24 (火) 19:43:02
#! /usr/bin/python # -*- coding: euc-jp -*-; import sys def main(): file = sys.argv[1] f = open(file, "r") lines = f.readlines() for line in lines: print "before:", line t = line.decode('euc-jp') print "after :", t tt = t.encode('euc-jp').replace("~", "〜") print "convd :", tt if ( __name__ == "__main__" ): main()
Emacs 上ではこういう結果になった。
% ./test.py a before: A□B after : A~B convd : A〜B before: C□D after : C~D convd : C〜D
この結果を見ると、Pythonの世界で 8f a2 b7 というシークエンスを EUC-JP として decode するとUTF的には普通のチルダ(~) になって、その状態で"~"を"〜"に変換して EUC-JP に encode してやれば本来のコードになるみたい
hexdump で見ても、
% ./test.py a | hexdump -C 00000000 62 65 66 6f 72 65 3a 20 41 8f a2 b7 42 0a 0a 61 |before: A...B..a| 00000010 66 74 65 72 20 3a 20 41 7e 42 0a 0a 63 6f 6e 76 |fter : A~B..conv| 00000020 64 20 3a 20 41 a1 c1 42 0a 0a 62 65 66 6f 72 65 |d : A..B..before| 00000030 3a 20 43 8f a2 b7 44 0a 0a 61 66 74 65 72 20 3a |: C...D..after :| 00000040 20 43 7e 44 0a 0a 63 6f 6e 76 64 20 3a 20 43 a1 | C~D..convd : C.| 00000050 c1 44 0a 0a |.D..| 00000054
ということで、初期状態は 8f a2 b7 が、euc-jp -> UTF8 すると 7e になって、UTF8の世界で s/~/〜/して euc-jpに戻すと a1 c1 になる、みたい。
とりあえず当初の目的だった 8f a2 b7 というコードを持ったファイル名を修正する方法はメドが立ったけど、 8f a2 b7 というシークエンスがgtk/Qtな世界だとeuc-jpの"〜"に解釈されるのはなぜか、というあたりはよく分からんし、 そもそもWindowsな世界で作ったファイル名がEUC-JPの世界で 8f a2 b7 になる、というのがよく分からんなぁ? -- kojima 2010-08-24 (火) 20:08:47
tt = t.encode('euc-jp').replace("~", "〜")
としてたけど、これは "〜" が euc-jp な世界なので、そっちに移す余計な処理が入るから、
tt = t.replace("~", u'〜')
の方が正しいか。-- kojima 2010-08-24 (火) 21:59:15