以前Perlでもやりましたが、文字コードの自動検出に関して。
ちなみにcp932=SJIS-WINです。
参考リンク
PHPの場合、mb_detect_encodingという文字コード検出の関数があるらしいのですが、どうやらあまり当てはまらないらしく、頼れないようです(汗)
今回はテキストファイル(文字コード不明、ただし実際はsjisかutf8)を読み込みutf8に変換するって処理が必要だったんですが、元のエンコーディングがわからないとどうしようもないです。
で、色々調べたところmb_language('Ja')
+mb_convert_encoding($file_contents, 'UTF-8','ASCII,JIS,UTF-8,EUC-JP,SJIS-WIN,SJIS');
でいけるようです。
mb_convert_encoding($file_contents, 'UTF-8','auto')
という手法もありますが、autoよりも実際の文字コードを列挙するほうが精度が高いようです。
*特にSJIS-WINはSJISより前においたほうがいいようです。SJIS-WINにあってSJISにないものを検知できるので。
1 2 3 4 5 6 7 8 9 10 11 12 |
mb_language('Ja'); #これを書かないとWarning: mb_convert_encoding(): Unable to detect character encoding $res = file_get_contents('cp932_text.txt'); #正確に検知できる $res = mb_convert_encoding($file_contents, 'UTF-8','ASCII,JIS,UTF-8,EUC-JP,SJIS-WIN,SJIS'); var_dump($res); #string(22) "本日は晴天あり #utf8ももちろん問題なし $res = file_get_contents('utf8_text.txt'); $res = mb_convert_encoding($file_contents, 'UTF-8','ASCII,JIS,UTF-8,EUC-JP,SJIS-WIN,SJIS'); var_dump($res); #string(22) "本日は晴天あり |
mb_convert_encodingで第3引数には元々のエンコーディングを書きますが、これがautoになっていると複数の文字コードからPHPが検出テストを行い、この文字コードであろうという推測を行います。
列挙する場合、先頭の文字コードから順にチェックをしていくようです。だからSJIS-WNをSJISの前にしたほうが都合がいいかもしれません。
(おそらく100%ではないと思います。vimも自動検出機能がありますが、たまに間違えますが、同じことだと思います。だから文字コードがわかっていれば第3引数は文字コードをセットするのが当然無難です。)
が、通常だとSJIS-WINが候補にないのかUnable to detect character encoding
というエラーがでてしまいます。
そこでmb_language('Ja')
をセットすることでSJIS-WINが検出できるようになります。
mb_convert_encodingのautoが危険な理由
またmb_substrのような関数がありますが、おそらくPHP内部でマルチバイトに対して特殊なフラグを設定しているものと思われます。
ここら辺Perlはしっかりと分けて判定しないくてはいけないので面倒な分、理解せざるを得ませんでした。
参考リンク