PHP 无法正确解析 CSV(文件为 UTF-16LE)
PHP cannot parse CSV correctly (file is in UTF-16LE)
我正在尝试使用 PHP 解析 CSV 文件。
该文件使用 逗号作为分隔符 和 双引号用于包含逗号 的字段,如:
foo,"bar, baz",foo2
我面临的问题 是我得到的字段包含逗号分隔。我得到:
"2
rue du ..."
而不是:2, rue du ...
.
编码:
该文件似乎不是 UTF8 格式。它的开头有奇怪的字符(,从 ASCII 转换为 UTF8 时看起来像这样:ÿþ
)并且不显示重音符号。
- 我的代码编辑器 (Atom) 告诉我编码是 UTF-16 LE
- 在 csv 行上使用
mb_detect_encoding()
returns ASCII
但是转换失败:
mb_convert_encoding()
从 ASCII
转换而来 returns 亚洲字符从 UTF-16LE
iconv()
returns 注意:iconv(): 错误的字符集,从 UTF-16LE
/ASCII
到 UTF8
的转换不是允许.
解析:
我尝试使用 str_getcsv()
:
来解析这一行(参见 those 2 comments)
$csv = array_map('str_getcsv', file($file['tmp_name']));
然后我尝试使用 fgetcsv()
:
$f = fopen($file['tmp_name'], 'r');
while (($l = fgetcsv($f)) !== false) {
$arr[] = $l;
}
$f = fclose($f);
在这两种方式中,我都将我的地址字段分为两部分。但是当我尝试这个代码示例时,我得到了正确解析的字段:
$str = 'foo,"bar, baz",foo2,azerty,"ban, bal",doe';
$data = str_getcsv($str);
echo '<pre>' . print_r($data, true) . '</pre>';
用问题来总结:
- 文件开头的字符是什么?
- 我如何确定编码? (Atom读取
UTF-16 LE
文件,开头不显示怪异字符)
- 是什么导致 csv 解析函数失败?
- 如果我应该依靠其他东西来解析 CSV 的行,我可以使用什么?
终于自己解决了:
我将文件发送到在线编码检测网站,结果返回 UTF16LE。在检查了什么是 UTF16LE 之后,它说它有 BOM(字节顺序标记).
我之前的尝试是使用 file()
其中 returns 一个 行数组 文件和 fopen()
其中 returns 一个资源,但我们仍然逐行解析 .
我想到的工作解决方案是 转换整个文件(一次转换每一行) 而不是分别转换每一行。这是一个可行的解决方案:
$f = file_get_contents($file['tmp_name']); // Get the whole file as string
$f = mb_convert_encoding($f, 'UTF8', 'UTF-16LE'); // Convert the file to UTF8
$f = preg_split("/\R/", $f); // Split it by line breaks
$f = array_map('str_getcsv', $f); // Parse lines as CSV data
我不再使用内部逗号分隔地址字段。
我正在尝试使用 PHP 解析 CSV 文件。
该文件使用 逗号作为分隔符 和 双引号用于包含逗号 的字段,如:
foo,"bar, baz",foo2
我面临的问题 是我得到的字段包含逗号分隔。我得到:
"2
rue du ..."
而不是:2, rue du ...
.
编码:
该文件似乎不是 UTF8 格式。它的开头有奇怪的字符(ÿþ
)并且不显示重音符号。
- 我的代码编辑器 (Atom) 告诉我编码是 UTF-16 LE
- 在 csv 行上使用
mb_detect_encoding()
returns ASCII
但是转换失败:
mb_convert_encoding()
从ASCII
转换而来 returns 亚洲字符从UTF-16LE
iconv()
returns 注意:iconv(): 错误的字符集,从UTF-16LE
/ASCII
到UTF8
的转换不是允许.
解析:
我尝试使用 str_getcsv()
:
$csv = array_map('str_getcsv', file($file['tmp_name']));
然后我尝试使用 fgetcsv()
:
$f = fopen($file['tmp_name'], 'r');
while (($l = fgetcsv($f)) !== false) {
$arr[] = $l;
}
$f = fclose($f);
在这两种方式中,我都将我的地址字段分为两部分。但是当我尝试这个代码示例时,我得到了正确解析的字段:
$str = 'foo,"bar, baz",foo2,azerty,"ban, bal",doe';
$data = str_getcsv($str);
echo '<pre>' . print_r($data, true) . '</pre>';
用问题来总结:
- 文件开头的字符是什么?
- 我如何确定编码? (Atom读取
UTF-16 LE
文件,开头不显示怪异字符) - 是什么导致 csv 解析函数失败?
- 如果我应该依靠其他东西来解析 CSV 的行,我可以使用什么?
终于自己解决了:
我将文件发送到在线编码检测网站,结果返回 UTF16LE。在检查了什么是 UTF16LE 之后,它说它有 BOM(字节顺序标记).
我之前的尝试是使用 file()
其中 returns 一个 行数组 文件和 fopen()
其中 returns 一个资源,但我们仍然逐行解析 .
我想到的工作解决方案是 转换整个文件(一次转换每一行) 而不是分别转换每一行。这是一个可行的解决方案:
$f = file_get_contents($file['tmp_name']); // Get the whole file as string
$f = mb_convert_encoding($f, 'UTF8', 'UTF-16LE'); // Convert the file to UTF8
$f = preg_split("/\R/", $f); // Split it by line breaks
$f = array_map('str_getcsv', $f); // Parse lines as CSV data
我不再使用内部逗号分隔地址字段。