处理含JSON字段的CSV时反斜杠导致键值映射异常问题
问题:CSV含带反斜杠的JSON字段导致键值映射异常
我正在处理一个CSV文件,其中某列包含JSON格式数据,该JSON里部分字段带有反斜杠,导致后续键值映射出现问题。前两行数据处理正常,但从第三行开始,“Event Value”列的带反斜杠JSON数据引发了映射错误。
当前代码
$file_name = 'new_testing.csv'; $file_path = '/var/www/html/'.$file_name; $file_content = file_get_contents($file_path); $file = new SplFileObject($file_path); $file->setFlags(SplFileObject::READ_CSV | SplFileObject::READ_AHEAD | SplFileObject::SKIP_EMPTY); // Read and skip the headers $headers = $file->fgetcsv(); // Process the data $chunkSize = 5000; // Set the desired chunk size $loop = 0; $chunkData = []; while (!$file->eof()) { // Read the next chunk of lines for ($i = 0; $i < $chunkSize && !$file->eof(); $i++) { $line = $file->fgetcsv(); if ($line) { // Sanitize each field in the line to remove backslashes and double quotes $line = array_map(function ($field) { return str_replace(['\', '"'], '', $field); }, $line); // Adjust the number of elements in $line to match the number of headers if (count($line) < count($headers)) { // Fill missing values with null or empty strings $line = array_pad($line, count($headers), null); } elseif (count($line) > count($headers)) { // Trim extra values $line = array_slice($line, 0, count($headers)); } // Combine headers and line values into an associative array $row = array_combine($headers, $line); $chunkData[] = $row; } } } echo "<pre>"; print_r($chunkData);
问题根源
SplFileObject::fgetcsv()默认解析逻辑会把反斜杠当作转义符,导致包含反斜杠的JSON字段被错误拆分,使$line数组元素数量和表头不匹配,最终array_combine抛出映射错误。另外,当前代码盲目删除反斜杠和引号的操作会直接破坏JSON结构,后续即使拆分正确也无法解析JSON。
解决方案
方案1:自定义CSV字段解析,保证字段完整性
绕过fgetcsv()的默认解析,用正则匹配正确拆分带特殊字符的字段:
$file = new SplFileObject($file_path); $file->setFlags(SplFileObject::SKIP_EMPTY); $headers = $file->fgetcsv(); $chunkData = []; $chunkSize = 5000; while (!$file->eof()) { for ($i = 0; $i < $chunkSize && !$file->eof(); $i++) { $line = $file->fgets(); if (empty($line)) continue; // 正则匹配CSV字段,兼容带转义符的引号包裹字段 preg_match_all('/(?:^|,)(?:"(?:\\\\.|[^"])*"|[^",]*)/', $line, $matches); $fields = array_map(function($field) { // 清理字段首尾的逗号和空白符 $field = trim($field, ", \t\n\r"); // 处理被引号包裹的字段,还原转义内容 if (str_starts_with($field, '"') && str_ends_with($field, '"')) { $field = substr($field, 1, -1); $field = stripslashes($field); } return $field; }, $matches[0]); // 对齐字段数量与表头 if (count($fields) < count($headers)) { $fields = array_pad($fields, count($headers), null); } elseif (count($fields) > count($headers)) { $fields = array_slice($fields, 0, count($headers)); } // 可选:解析Event Value列的JSON $eventValueKey = array_search('Event Value', $headers); if ($eventValueKey !== false && !empty($fields[$eventValueKey])) { $fields[$eventValueKey] = json_decode($fields[$eventValueKey], true) ?: $fields[$eventValueKey]; } $row = array_combine($headers, $fields); $chunkData[] = $row; } } echo "<pre>"; print_r($chunkData);
方案2:预处理CSV内容,修正转义逻辑
先修正CSV中JSON字段的转义问题,再用标准方法解析:
$file_content = file_get_contents($file_path); // 确保JSON字段内的转义符被正确处理,避免CSV解析时拆分错误 $file_content = preg_replace_callback('/"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"/', function($matches) { return '"' . addslashes(stripslashes($matches[1])) . '"'; }, $file_content); // 创建临时文件处理修正后的内容 $tempFile = tempnam(sys_get_temp_dir(), 'csv_fix_'); file_put_contents($tempFile, $file_content); $file = new SplFileObject($tempFile); $file->setFlags(SplFileObject::READ_CSV | SplFileObject::READ_AHEAD | SplFileObject::SKIP_EMPTY); $headers = $file->fgetcsv(); $chunkData = []; $chunkSize = 5000; while (!$file->eof()) { for ($i = 0; $i < $chunkSize && !$file->eof(); $i++) { $line = $file->fgetcsv(); if ($line) { // 解析Event Value列的JSON $eventValueKey = array_search('Event Value', $headers); if ($eventValueKey !== false && !empty($line[$eventValueKey])) { $line[$eventValueKey] = json_decode($line[$eventValueKey], true) ?: $line[$eventValueKey]; } // 对齐字段数量 if (count($line) < count($headers)) { $line = array_pad($line, count($headers), null); } elseif (count($line) > count($headers)) { $line = array_slice($line, 0, count($headers)); } $row = array_combine($headers, $line); $chunkData[] = $row; } } } unlink($tempFile); // 删除临时文件 echo "<pre>"; print_r($chunkData);
注意事项
- 禁止盲目删除反斜杠或引号,这会破坏JSON结构,导致后续无法解析。
- 优先保证CSV字段拆分的正确性,再处理JSON内容的解析。
内容的提问来源于stack exchange,提问作者Siddhart hundare
相关产品推荐
相关产品推荐

