最近直面した5C問題をメモとしてまとめておこうと思います。
5C問題とは
日本語は、ひらがな、カタカナ、漢字など文字数も多く、1バイト(256種類)では
すべての文字を表現することは難しいため、ShiftJIS
では、漢字を1文字当たり2バイトを
使って文字情報を表します。
ここで問題なのが、「¥」
、「 \ 」
の文字コードが「5c」であり、
一部の漢字の文字コードが重複しているため、コンピュータはその箇所を
エスケープ記号として解釈することにより正常に読み取れなくなっている。
文字 | Shift-JISコード | |
---|---|---|
噂 | 89 | 5c |
予 | 97 | 5c |
兔 | 99 | 5c |
こちらの文字コード表を参考
コードで確認
PHPでShiftJIS
の「兔」の文字の値を見てみる。
$str = mb_convert_encoding('兔', 'SJIS', 'UTF-8');
var_dump($str);
// 出力結果: string(2) "�¥"
エスケープ文字の「¥」
が表示された。
これは、コンピュータが「兔」の文字コード「5c」
の箇所を「¥」
として
解釈したためである。
このままの状態でプログラムを書くと予期せぬエラーが発生する可能性がある。
想定されるエラー
例として、CSVデータ取得処理のときファイルがShift-JIS
で
特定の文字を使っているときを想定し、PHPのfgetcsvメソッド
を使用してデータを取得する。
$temp = tmpfile();
$str = mb_convert_encoding('"兔"', 'SJIS', 'UTF-8');
var_dump($str);
// 出力結果: string(4) ""�¥""
fwrite($temp, $str);
var_dump(fgetcsv($temp));
// 出力結果: bool(false)
$str
の値には""�¥""
がはいっており、これを解釈すると
「¥」
の次の「"」
がエスケープされ、形式が崩れてしまうことで
fgetcsvメソッド
はfalse
を返してしまう。
回避するには
- 文字コードを
ShiftJIS
をUTF-8
へ変換する。 - 各言語で変換するためのロジックを組む必要がある。
PHPであれば、file_get_contentsメソッド
でファイル全体を文字列に読み込んだ後に
mb_convert_encodingメソッド
でUTF-8
へ変換する。
又は、ストリームフィルタ機能
を使ってphp_user_filterクラス
を継承したクラスを
生成した後にfilterメソッド
を定義して変換する処理を書く。
感想
文字コードの問題は頭の片隅に置いといて
ファイル読み込みの際は、対策を考慮しないといけないですね。
ストリームフィルタを作るのは結構大変そうなので
調べて別の記事に注意点などメモとしてまとめたいなと思います。