

こんにちは。  
中国語と日本語が混在しているshift jis
winのcsvをphpで以下のようにして読み込もうとしているのですが、中国語だけ文字化けしてしまうのですが、どのようにすればutf-8で読み込めるのでしょうか。  

[FYI] csv自体はプロジェクトの都合によりshift jis winで保存しなければいけないので、shift jis
win->utf-8の変換をしたい感じとなります。

■ csv

[code]

    言葉, 中国語訳
    こんにちは, 您好
    ありがとう, 谢谢啦
    
[/code]

■ csvの16進ダンプ

[code]

    $ hexdump -x ./test.csv
    0000000    be8c    7497    922c    8d86    8c91    96ea    0af3    b182
    0000010    f182    c982    bf82    cd82    3f2c    448d    820a    82a0
    0000020    82e8    82aa    82c6    2ca4    3f3f    0a3f
    000002c
    
[/code]

[code]

    $ xxd ./test.csv
    00000000: 8cbe 9774 2c92 868d 918c ea96 f30a 82b1  ...t,...........
    00000010: 82f1 82c9 82bf 82cd 2c3f 8d44 0a82 a082  ........,?.D....
    00000020: e882 aa82 c682 a42c 3f3f 3f0a            .......,???.
    
[/code]

■ ソース

[code]

    <?php
    if (($handle = fopen($argv[1], "r")) !== FALSE) {
        while (($data = fgetcsv($handle))) {
            foreach ($data as $value) {
                mb_convert_variables('utf-8','sjis-win', $value);
                echo "${value},";
            }
            echo "\n";
        }
        fclose($handle);
    }
    
[/code]

■ 出力

[code]

    言葉,中国語訳,
    こんにちは,?好,
    ありがとう,???,
    
[/code]


CC BY-SA 4.0
2020-01-04T11:09:31.233
61966
2022-02-18T13:04:45.443
2020-01-04T12:17:40.123
10222
10222
question
php csv shift-jis locale
中国語と日本語が混在しているcsv(shift jis win)をphpで読み込み方法について


## tl;dr

CSVにBOMをつけたらどうですか？

### CSV出力コード

[code]

    <?php
    
    $fp = fopen('test.csv', 'wb');
    
    $list = [
        ['言葉', '中国語訳'],
        ['こんにちは', '您好'],
        ['ありがとう', '谢谢啦'],
    ];
    
    // Prepend BOM
    fputs($fp, $bom =( chr(0xEF) . chr(0xBB) . chr(0xBF) ));
    
    foreach ($list as $fields) {
        fputcsv($fp, $fields);
    }
    
    fclose($fp);
    
[/code]

### CSV入力コード

[code]

    <?php
    
    $fp = fopen('test.csv', 'r');
    $bom = chr(0xEF) . chr(0xBB) . chr(0xBF);
    
    if ($fp !== FALSE) {
        $encoding = 'UTF-8';
        if (fgets($fp, 4) !== $bom) {
            rewind($fp);
            $encoding = 'SJIS-WIN';
        }
    
        while (($data = fgetcsv($fp)) !== FALSE) {
            foreach ($data as $value) {
                mb_convert_variables('UTF-8', $encoding, $value);
                echo "${value},";
            }
            echo "\n";
        }
    
        fclose($fp);
    }
    
[/code]

* * *

## やや長い説明

Shift_JIS（及びMSによる拡張を含むCP932）には中国語の「您」「谢」「啦」といった漢字が含まれていません。そのため、少なくともこれらの文字を含むShift_JISのCSVファイルというものは存在しません。

提示されているCSVは16進ダンプを見る限り、Shift_JISとして表現できない文字はすべてCSVの段階でリテラルの `? (3f)`
に変換されており、もとの中国語の情報はすでに失われています。ですので、CSVへの保存の仕方を考え直す必要があるでしょう。

CSVを保存する必要があり、しかもそれがShift_JIS縛りになっているのは、大半が「Excelで保存されているCSVを表示/確認したい」という要望の為だと思います。ExcelはBOMが付与されている場合に限りUTF-8のCSVファイルを正しく読むことができます。

上のコードはそのようなExcelのクセをPHPで真似たものです。入力コードをBOM付きUTF-8に対応させ、互換性のため既存のShift_JISのCSVを読めるようにしておきます。


CC BY-SA 4.0
2020-01-04T13:23:07.620
61971
2020-01-04T13:23:07.620
62
61966
answer