PHP处理CSV格式转换:解决表头排序、值匹配及缺失值填充问题
需求说明
我有一个特殊格式的CSV数据集,内容如下:
key=value,key2=value,key3=value key=value,key2=value,key4=value,key3=value
需要将其转换为标准CSV格式,要求:
- 表头包含所有出现过的键,且排序后输出
- 每行对应的值要匹配表头的列顺序
- 缺失的列值用字符串
null填充
期望输出格式:
key,key2,key3,key4 value,value,value,null value,value,value,value
我自己写了一段PHP代码,但转换后存在数组不匹配的问题,代码如下:
if (($handle = fopen("sheet4.csv", "r")) !== FALSE) { while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) { $cols = explode(",", $data[0]); $num = count($cols); for ($c = 0; $c < $num; $c++) { $colData = explode("=", $cols[$c]); $outputHeaders[$row][$colData[0]] = $colData[0]; $output[$row][$colData[0]] = $colData[1]; } $csvOutput[$row] = array_combine($outputHeaders[$row], $output[$row]); $row++; } fclose($handle); } foreach ($csvOutput as $row => $rowData) { $extractHeaders[] = array_keys($rowData); } $mergedHeaders = array_unique(call_user_func_array('array_merge', $extractHeaders)); $fp = fopen('sheet4out.csv', 'wa'); fputcsv($fp, $mergedHeaders); foreach ($csvOutput as $key => $fields) { $rowKeys = array_keys($fields); if (count($mergedHeaders) == count($rowKeys)) { } else { $differntKeys = array_diff($mergedHeaders, $rowKeys); $fields = array_merge($fields, array_fill_keys($differntKeys, 'banana')); } fputcsv($fp, $fields); }
请帮忙修正代码实现需求。
修正后的代码及说明
原始代码问题
- 重复解析CSV行:用
fgetcsv读取后又调用explode(",", $data[0]),多余且可能破坏字段含逗号的解析逻辑 - 表头未排序:合并后直接输出,无法保证列顺序统一
- 列对应错误:填充缺失值后未按表头顺序重新排列数组,导致值和列不匹配
- 文件模式不规范:
wa不是标准PHP文件打开模式,应使用w(覆盖写入) - 变量未初始化:
$row未定义就使用,会引发索引错误 - 键值分割不严谨:
explode("=")未限制分割次数,若值中包含=会导致数据错误
修正后的代码
<?php // 初始化存储变量 $allRows = []; $allHeaders = []; // 读取原始CSV文件 if (($handle = fopen("sheet4.csv", "r")) !== FALSE) { while (($line = fgets($handle)) !== FALSE) { // 去除行尾换行符,分割为key=value对 $pairs = explode(",", trim($line)); $rowData = []; foreach ($pairs as $pair) { // 限制分割次数为2,避免值中含=导致错误 list($key, $value) = explode("=", $pair, 2); $rowData[$key] = $value; // 收集所有出现过的表头键 $allHeaders[$key] = true; } $allRows[] = $rowData; } fclose($handle); } // 对表头进行排序,保证列顺序稳定 ksort($allHeaders); $finalHeaders = array_keys($allHeaders); // 生成目标CSV文件 $fp = fopen('sheet4out.csv', 'w'); // 写入排序后的表头 fputcsv($fp, $finalHeaders); // 处理每一行数据,按表头顺序填充值 foreach ($allRows as $row) { $outputRow = []; foreach ($finalHeaders as $header) { // 存在对应值则取,否则填充null $outputRow[] = isset($row[$header]) ? $row[$header] : 'null'; } fputcsv($fp, $outputRow); } fclose($fp); ?>
核心改进
- 改用
fgets读取整行,避免fgetcsv自动解析的干扰,同时用trim清理换行符 - 用
explode("=", $pair, 2)分割键值对,兼容值中包含=的场景 - 收集所有表头后用
ksort排序,确保输出列顺序统一 - 遍历排序后的表头生成每行数据,严格保证值与列的对应关系
- 规范文件打开模式为
w,确保每次生成全新的目标文件 - 初始化所有变量,避免未定义变量错误
内容的提问来源于stack exchange,提问作者Yubhu
相关产品推荐
相关产品推荐

