2012-03-24

fgets()でUTF-16LEのファイルを読む

fgets()でUTF-16LEのファイルを読んだときにハマったお話。



fgets()は、第2引数を省略した場合、

・改行文字 (0x0A) を検出した

又は

・EOFに達した

場合に読み出しを終える。


ここに

123改行
123改行
EOF

というBOM無しファイルがあったとする。


UTF-16BEのバイト配列は

00 31 00 32 00 33 00 0A
00 31 00 32 00 33 00 0A



UTF-16LEのバイト配列は

31 00 32 00 33 00 0A 00
31 00 32 00 33 00 0A 00


となる。


このBOM無しUTF-16LEファイルを次のように読むと、

$fp = fopen("UTF16LE.txt", "r");

$bf = fgets($fp); // (1)

$bf = fgets($fp); // (2)



(1)の結果は
31 00 32 00 33 00 0A

(2)の結果は
00 31 00 32 00 33 00 0A

となる。

(1) は 0x0A を検出した時点で読み出しを止め、変数 $bf へ結果を返している。
(2) は、(人から見た)1行目の「0x0A」の次の 0x00 から読み出しが開始されるため、バイトオーダーが反転した(LE からBEに変わった)ような錯覚に陥る。



そう、ここで錯覚に陥ったのがすべての始まり。



文字化けが発生しないように、マルチバイト文字列関数を使う際は必ず文字エンコードを指定するようにしているが、これは困ったことになった。



2行目以降はUTF-16BEで処理するかとか、いろいろ悩んだけど、結局


$file = file_get_contents("UTF-16LE.txt");

mb_convert_variables("UTF-16BE", "UTF-16LE", $file);



こうやってファイル全体の文字エンコードを、UTF-16BE に変換してから後の処理を行うことにした。



これね、既存のシステムから出力されるファイルを取り込んで云々の仕事をしたときの話。

0 件のコメント:

コメントを投稿

Chatの「メッセージは投稿者によって削除されました」を非表示にする方法

Chrome拡張機能を自作してやってみよう! ♪できるかな できるかな ・・・ 無理ぽ (´・ω・`) iframeの中に、実際のメッセージのやり取りが表示されるので、 $(function(){ $('iframe[name^="spa...