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 件のコメント:

コメントを投稿

綺麗に見せることに全振りした操法大会の訓練を50日間するよりも、月1回でいいから基本的な操作方法の訓練を実施すべきだと思うのは俺だけか

 7月に県の消防操法大会がある。 市内分団の持ち回り制で、今年はうちの分団が出場する。 俺も前回回ってきたときに、選手として出た。 訓練が5月から始まっている。 週5日。 訓練時間は2時間だけど、その前に準備する時間もあり、訓練後の撤収時間も必要だから、拘束時間は約3時間。 俺が...