Чтение UNICODE CSV с использованием PHP

Мне приходится сталкиваться с проблемой чтения символов Unicode из CSV-файла с помощью PHP.

Ниже приведен скриншот файла ccv UNICODE.

введите описание изображения здесь

Код PHP, который я использую, приведен ниже.

$delimiter = ","; $row = 1; $handle = fopen($filePath, "r"); while (($data = fgetcsv($handle, 1000, $delimiter)) !== FALSE) { $num = count($data); $row++; for ($c=0; $c < $num; $c++) { echo $data[$c]; } } fclose($handle); 

Для приведенного выше кода я получаю снизу как вывод в браузере Chrome. У него есть ненужные символы.

введите описание изображения здесь

Но если я добавлю символ новой строки в оператор эха, как показано ниже, он даст правильный результат.

 echo $data[$c]."\n"; 

введите описание изображения здесь

Почему он ведет себя так? Я не хочу добавлять новую строку вроде этого.

UNICODE csv-файл.

Кодировка, которую Windows вызывает «Unicode» (ошибочно, Unicode не является кодировкой) на самом деле является UTF-16LE. Это кодировка с двумя байтами на код, поэтому символы ASCII выходят в виде байта ASCII, за которым следует нулевой байт.

Функция fgetcsv PHP не поддерживает CSV UTF-16, она поддерживает только кодировки, совместимые с ASCII. Он разбивается на каждый байт 0x0A (новая строка) и 0x2C (запятая), но в UTF-16LE и новая строка и запятая являются двухбайтными последовательностями, 0x0A 0x00 и 0x2C 0x00 соответственно. Это означает, что вы получаете ведущие одиночные 0x00 байт в передней части каждого поля, но первый, и вы получаете неправильное разделение, когда значение содержит байты 0x0A или 0x2C, которые не являются частью новой строки / запятой UTF-16.

Когда вы печатаете это на выходе с кодировкой UTF-16LE, дополнительный 0x00 байт помещает каждое поле из двухбайтового выравнивания с последним, что означает, что просмотр в браузере видит переменные поля как несогласованные и печатает бессмысленные символы состоящий из младшего байта одного символа с байтом следа того, который был перед ним.

Таким образом, вы можете сделать две вещи:

  • если у вас есть выбор в этом вопросе, избегайте UTF-16. Поскольку он не совместим с ASCII, он разбивает множество инструментов, которые ожидают этого. Как правило, лучшим кодированием является UTF-8, который может включать в себя все символы и по-прежнему быть ASCII-надмножеством … к сожалению, Excel отказывается сохранять CSV-файлы непосредственно в UTF-8.

  • используйте другой синтаксический анализатор CSV, который понимает UTF-16. Это хорошая идея, чтобы избежать CSV-функций PHP в любом случае, потому что они делают странные вещи, которые не соответствуют стандартным CSV (в той мере, в какой существует стандарт … по крайней мере, это не соответствует RFC 4180 и тому, что производит Excel).

Попробуйте добавить это, прежде чем показывать текст

 header('Content-Type: text/html; charset=utf-8'); $delimiter = ","; $row = 1; $handle = fopen($filePath, "r"); while (($data = fgetcsv($handle, 1000, $delimiter)) !== FALSE) { $num = count($data); $row++; for ($c=0; $c < $num; $c++) { echo $data[$c]; } } fclose($handle);