UTF-16LEをUTF-8に変換したら末尾の文字が消える

2012/01/09 | その他

ウェブアプリを作っていて、Excelからの出力ファイルを、設定ファイル等に使用したい時がある。そんな時にExcelからの出力形式でCSVやタブ区切りテキスト等を使うことも多いかと思うが、日本語の場合シフトJISで出力される。この場合、もちろんPHP側で読み込む際に文字コード変換すればいいのだが、日本語じゃなくて韓国語とか中国語とか含まれていた場合でも上手く対応できないか、と考えた。

Excelにはunicodeで出力するオプションが用意されていて、これを選ぶとタブ区切りで文字コードUTF-16LEのBOMつき、拡張子txtでファイルを出力してくれる(ちなみに拡張子をcsvに変更すると、当該ファイルのダブルクリックでExcelが自動起動してくれるので便利)。マルチバイトで使用する場合は一番便利がよさそう。

でもまぁ、UTF-8への変換は必要になる。そこで以下のようなコードを書いてみた。読み込み元ファイルのtest.txtにはtestと記述しておいた(上述のようにUTF-16LE、BOMつきのファイルとしてある)。

$str = file_get_contents(‘test.txt’);
var_dump($str);
$str = substr($str,2);
var_dump($str);
$str = trim($str);
var_dump($str);
$str=mb_convert_encoding($str,’UTF-8′,’UTF-16LE’);
var_dump($str);

見ての通り、(1)読み込んで、(2)BOMを取り除いて、(3)前後の空白文字を取り除いて、(4)文字コード変換して、というステップだ。出力された結果はこんな感じ。

string(10) “ÿþtest”
string(8) “test”
string(7) “test”
string(3) “tes”

最初のデータで、文字列の前についているゴミはBOM(UTF-16LEの場合は2バイトがBOM)。気になるのは(4)の処理後に最後の文字が欠落してしまっていることだ。で、調べてみた。

どうもUTF-16LEでは各文字の後ろに、何かはわからないけれど制御文字が入っているっぽい。(2)と(3)の結果を見ると、trimで明らかに1バイト減っている。UTF-16LEでは、この制御文字までを含めて一つの文字となっているようだ。(4)の処理後に最後の文字が欠落するのは、trimした結果制御文字がなくなってしまい、最後の文字である「t」が不完全となったため、欠落してしまったようだ。ちなみに制御コードをord関数を使って出力したら「0」となっていた。ヌル文字のようだ。

文字の構造を理解していなくて、上記の問題にぶつかったわけだけど、少し勉強になった。なんでもかんでもtrimすりゃいいってもんじゃないことを今頃理解した次第。

コメントを残す


守谷市(まちの情報ポータル) 無料アンケートレンタルjpForm.net