文字コードを変換するコードを書いていて、表題の通り、ハマりましたので、備忘録として書いておきます。
環境
- OS: Amazon Linux2
- PHP: 7.4.14
詳細
UTF-8のファイルをもとに、SJISでファイル出力するコードを書きました(確認用のコードも含めてます)。
$data_org = file_get_contents('./files/utf8_sample.csv');
echo "変換前の文字コード:".mb_detect_encoding($data_org,"UTF-8, ASCII, SJIS")."\n";
file_put_contents('./files/sjis_sample.csv', mb_convert_encoding($data_org, "SJIS"), FILE_APPEND | LOCK_EX);
$data_conv = file_get_contents('./files/sjis_sample.csv');
echo "変換後の文字コード:".mb_detect_encoding($data_conv,"UTF-8, ASCII, SJIS")."\n";
半角英数のみのファイルを用いた場合
変換前のファイルの内容は以下の通り。文字コードはUTF-8です。
id,sex,age,amount,category
00000003,m,31,00002001,food
00000003,m,31,00007569,clothes
00000012,f,24,00001482,clothes
00000013,m,41,00012349,other
00000016,f,53,00001297,book
00000016,f,53,00005264,food
で、変換前のファイルを所定の場所に置き、PHPファイルを実行すると、以下のような結果に。
$ php fileEncoding.php
変換前の文字コード:UTF-8
変換後の文字コード:UTF-8
ん? 変換されてない?
調べていくうちに、半角英数の場合は、どの文字コードでも(今回の比較対象:JIS, SJIS, EUC, UTF-8, UTF-16)、同じ文字数字の組み合わせになることが判明(当たり前っちゃ当たり前な気もしますが)。
辺りを見ると、一目瞭然!
文字エンコーディングを検出する関数mb_detect_encodingでは、第2引数に指定した文字エンコーディングをリストを先頭から順番に一致するものがないか検索するようなので、試しに、convertEncoding.phpのmb_detect_encodingの第2引数の順序を変えてみるとコンソール出力結果は、以下のようになりました。
$ php fileEncoding.php
変換前の文字コード:ASCII
変換後の文字コード:ASCII
$ php fileEncoding.php
変換前の文字コード:SJIS
変換後の文字コード:SJIS
変換対象が半角英数の場合は、どの文字エンコーディングでも、表現が共通しているから、第2引数の先頭に指定したものに合致すると見なされるわけですね。
ちなみに、nkfコマンドで文字コードの確認をすると以下の通りに。
# 変換前のファイル
$ nkf --guess ./files/utf8_sample.csv
ASCII (CRLF)
# 変換後のファイル
$ nkf --guess ./files/utf8_sample.csv
ASCII (CRLF)
UTF-8も、SJISもASCIIの拡張だからかな・・?
日本語入りのファイルを用いた場合
原因が分かったところで、変換前のファイルの一部を日本語にしてみます。今回も、文字コードはUTF-8です。
id,sex,age,amount,category
00000003,m,31,00002001,食品
00000003,m,31,00007569,衣類
00000012,f,24,00001482,衣類
00000013,m,41,00012349,その他
00000016,f,53,00001297,本
00000016,f,53,00005264,食品
再度、convertEncoding.phpを実行!
$ php fileEncoding.php
変換前の文字コード:UTF-8
変換後の文字コード:SJIS
今度はうまくいきました!
nkfコマンドでも確認してみると・・・
$ nkf --guess ./files/utf8_sample.csv
UTF-8 (CRLF)
# 変換後のファイル
$ nkf --guess ./files/utf8_sample.csv
Shift_JIS (CRLF)
こちらも想定通り!!
結論
- 文字コードを正しく理解する!
- 文字コード変換するなら、対象の言語を用いる!
につきますね。