[PHP-users 21546]Re: 内部エンコードUTF8のファイルからUTF-16のCSVファイルを読み込む

KOYAMA Tetsuji koyama @ hoge.org
2004年 5月 6日 (木) 15:17:31 JST


  小山です。
  
At Thu, 06 May 2004 04:01:39 +0000,
aiko wrote:
> 以前、UTF-8でUTF-16のCSVファイルを読み込む方法で質問させていただきました。
> 小山様にアドバイスを元に、プログラムを記述してみましたが、
> 一部文字化けしてしまい上手くいきません。
> 日本語、ASCIIのみと両方試してみましたが、どちらも化けてしまいます。
> 小山様の環境では表示できた様ですが…
> どの様な原因が考えられるでしょうか。

  以前私がテストしたファイルは UTF-16BE (BOMなし) になっていました。岸
川さんのファイルはバイナリダンプを見ると UTF-16LE のようですので、その
ままでは fgets がうまく動きませんね。

  詳しく書くとこうです。
  fgets はファイルを読んでいって、16進で 0A が見つかったらそれまで読ん
だ内容を返します。

TEST1-1
TEST1-2

という内容のファイルがあったとして、これを UTF-16BE で表すとこうなりま
す。

00 54 00 45 00 53 00 54 00 31 00 2D 00 31 00 0A
00 54 00 45 00 53 00 54 00 31 00 2D 00 32 00 0A

各行が 0A で終わっているので、fgets は (偶然ですが) 正しく行の切れ目を
判断できます。そうして読み込んだ行を mb_convert_encoding で変換しても、
UTF-16BE として正しく認識できます。

ところが UTF-16LE のファイルだとこうなります。

54 00 45 00 53 00 54 00 31 00 2D 00 31 00 0A 00
54 00 45 00 53 00 54 00 31 00 2D 00 32 00 0A 00

0A まで読んだ部分を返すと、0A 00 の UTF-16LE としての改行コードが分割
されてしまい、最後の 00 が次の行の先頭に付いてしまいます。これでは
mb_conver_encoding に入力を UTF-16LE として指定しても、2行目以降は正し
く認識されません。

  これまででお分かりのように、原因は行の読み込みに fgets を使っている
せいです。UTF-16LE に対応した fgets などという便利なものはないので、自
分で作るか別のアプローチを考えなければいけません。

  とりあえず安直な方法ですが、ファイルを全て一度に読み込んでコード変換
する方法を提示します。ファイルのサイズが大きくなる場合は、このやり方だ
とメモリをバカ食いすることになりますので、より効率的な読み込み法を考え
て下さい。

$filename = 'utf16le.csv';
$contents = file_get_contents($filename);
$conv = mb_convert_encoding($contents, 'UTF-8', 'UTF-16LE');

$lines = explode("\n", $conv);

foreach ($lines as $line) {
    $data = explode(',', $line);
    print_r($data);
}

-- 
	小山 哲志@ビート・クラフト
	koyama @ beatcraft.com
	koyama @ hoge.org


PHP-users メーリングリストの案内