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

Я столкнулся с проблемой при чтении символов Unicode из файла CSV с использованием PHP.

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

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

Я использую код 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, как показано ниже, это даст правильный вывод.

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

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

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

1

Решение

UNICODE CSV-файл.

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

РНР fgetcsv Функция не поддерживает UTF-16 CSV, она поддерживает только кодировки, совместимые с 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. В любом случае, стоит избегать функций PHP CSV, потому что они делают странные вещи, которые не соответствуют стандарту CSV (поскольку существует стандарт … по крайней мере, он не соответствует RFC 4180 и тому, что производит Excel).

2

Другие решения

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

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);
0