PHP无法正确解析CSV(文件位于UTF-16LE中)

时间:2018-09-30 16:40:28

标签: php csv character-encoding byte-order-mark utf-16le

我正在尝试使用PHP解析CSV文件。
该文件使用逗号作为分隔符,并对包含逗号的字段使用双引号,例如:

foo,"bar, baz",foo2

问题,我面临的问题是我将包含逗号的字段分隔开了。我得到:

  • "2
  • rue du ..."

代替:2, rue du ...


编码:
该文件似乎不在UTF8中。它的开头有怪异的词句符(apparently not BOM,当从ASCII转换为UTF8:ÿþ时看起来像这样),并且不显示重音符号。

  • 我的代码编辑器(Atom)告诉编码为 UTF-16 LE
  • 在csv行上使用mb_detect_encoding()会返回 ASCII

但是无法转换:

  • mb_convert_encoding()ASCII进行转换,但从UTF-16LE返回亚洲字符
  • iconv()返回通知:iconv():错误的字符集,不允许从UTF-16LE / ASCIIUTF8的转换。 li>

解析:
我尝试使用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的行,那我该怎么用?

1 个答案:

答案 0 :(得分:1)

我终于自己解决了:

我将文件发送到在线编码检测网站,该网站返回了 UTF16LE 。在检查了什么是 UTF16LE 后,它说它具有 BOM(字节顺序标记)
我以前的尝试是使用file()返回文件的 行的数组 ,并使用fopen()返回资源,但是我们仍然解析 一行

我想到的解决方案是转换整个文件(一次一行),而不是分别转换每一行。这是一个可行的解决方案:

$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

我不再用内部逗号分隔地址字段。