最近直面した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メソッドを定義して変換する処理を書く。
感想
文字コードの問題は頭の片隅に置いといて
ファイル読み込みの際は、対策を考慮しないといけないですね。
ストリームフィルタを作るのは結構大変そうなので
調べて別の記事に注意点などメモとしてまとめたいなと思います。