使用 PHP 解析其中包含 JSON 的 CSV

Parse a CSV with a JSON in it using PHP

简介

我有一个 CSV 文件,其中每个字段都用双引号引起来 (")。每行的最后一个字段是 JSON 字符串表示形式。我想编写一个 PHP 脚本来解析 CSV 文件,然后解析 JSON 字符串。这就是我现在拥有的。

while (($line = fgetcsv($handle, 1000000, ";", '"')) !== false)
{
    // Another loop to loop over the fields
    // ...
    parse_json(end($line));
}

private function parse_json($json_string)
{
    if (!empty($json_string))
    {
        $json = json_decode($json_string, true);
        $msg = sprintf("The following description is not in proper JSON format: %s", $json_string);
        if (is_null($json))
        {
            // The function json_decode returns null if the string is not properly JSON formatted.
            throw new Exception($msg);
        }
    }
}

通过 CSV 文件中的以下行,我在 PHP 中得到以下数组。

"A";"B";"C";"D";"E";;"{""Name"":""Richard B Mephisto""}"
array ('Name' => 'Richard B Mephisto');

问题描述

当我想在 JSON 字符串的一个值中使用双引号时,问题就来了。对于 JSON,我需要用反斜杠转义双引号,而对于 CSV,我需要用另一个双引号转义双引号。如果我想要以下数组,CSV 文件和解析器应该是什么样子?

array ('Name' => 'Richard "B" Mephisto');

尝试失败

1) 在 CSV 文件中使用以下行。

"A";"B";"C";"D";"E";;"{""Name"":""""Richard B Mephisto""""}"

在解析 JSON 时,在调用 json_decode 之前,将每个 "" 替换为 /"。这在这种情况下有效,但我还需要允许空字符串。

"A";"B";"C";"D";"E";;"{""Name"":""}"

这些也将替换为此解决方案。

2) 在 CSV 文件中使用反斜杠。原则上,JSON 字符串应如下所示:

{"Name": "Richard \"B\" Mephisto"}

所以我在 CSV 文件中尝试这样做:

"A";"B";"C";"D";"E";;"{""Name"":\""Richard B Mephisto\""}"

结果为:

以下描述的 JSON 格式不正确:{"JSON_key":"Richard \"B\"" Mephisto""}"

不知何故,它不能与转义字符和双引号一起正常工作。

3) 转义 CSV 中的反斜杠。

"A";"B";"C";"D";"E";;"{""JSON_key"":""Richard \""B\"" Mephisto""}"

结果:

The following description is not in proper JSON format: {"JSON_key":"Richard \"B\" Mephisto"}

试试这个:

$in = '"A";"B";"C";"D";"E";;"{""Name"":""Richard \""B\"" Mephisto""}";"{""Name"":""""}"';
$out = str_getcsv($in, ';', '"', '"'); 
var_dump($out);

结果:

array(8) {
  [0]=>
  string(1) "A"
  [1]=>
  string(1) "B"
  [2]=>
  string(1) "C"
  [3]=>
  string(1) "D"
  [4]=>
  string(1) "E"
  [5]=>
  string(0) ""
  [6]=>
  string(33) "{"Name":"Richard \"B\" Mephisto"}"
  [7]=>
  string(11) "{"Name":""}"
}