PHP CSV字符串到数组
Posted
技术标签:
【中文标题】PHP CSV字符串到数组【英文标题】:PHP CSV string to array 【发布时间】:2013-07-19 15:06:25 【问题描述】:我正在尝试将 CSV 字符串解析为 php 中的数组。 CSV 字符串具有以下属性:
Delimiter: ,
Enclosure: "
New line: \r\n
示例内容:
"12345","Computers","Acer","4","Varta","5.93","1","0.04","27-05-2013"
"12346","Computers","Acer","5","Decra","5.94","1","0.04","27-05-2013"
当我尝试像这样解析它时:
$url = "http://www.url-to-feed.com";
$csv = file_get_contents($url);
$data = str_getcsv($csv);
var_dump($data);
最后一个元素和第一个元素连接在一个字符串中:
[0]=> string(5) "12345"
...
[7]=> string(4) "0.04"
[8]=> string(19) "27-05-2013
"12346""
我该如何解决这个问题?任何帮助将不胜感激。
【问题讨论】:
[2]=> string(48) "Acer"
, Acer
绝对不是 48 个字符长。如果确实格式正确,您可能需要检查您的输入。
出于隐私考虑,我编辑了内容,谢谢您的评论。
【参考方案1】:
这样做:
$csvData = file_get_contents($fileName);
$lines = explode(PHP_EOL, $csvData);
$array = array();
foreach ($lines as $line)
$array[] = str_getcsv($line);
print_r($array);
它会给你这样的输出:
Array
(
[0] => Array
(
[0] => 12345
[1] => Computers
[2] => Acer
[3] => 4
[4] => Varta
[5] => 5.93
[6] => 1
[7] => 0.04
[8] => 27-05-2013
)
[1] => Array
(
[0] => 12346
[1] => Computers
[2] => Acer
[3] => 5
[4] => Decra
[5] => 5.94
[6] => 1
[7] => 0.04
[8] => 27-05-2013
)
)
我希望这能有所帮助。
【讨论】:
工作就像一个魅力!非常感谢。 我很好奇,但有什么理由比 Gaui 下面的简单单行解决方案更好,还是人们只是因为它是选定的答案而投票赞成? 多行 CSV 字段失败 这可能会导致一个罕见的问题,如果值中包含换行符,那么PHP_EOL
会将值拆分为 2 个不同的数组值。
只使用fgetcsv()
!因为explode(PHP_EOL, $csvData)
没有正确解析 csv 字符串中的换行符!请参阅下面的正确答案。【参考方案2】:
您应该使用 fgetcsv。 由于 csv 是一个变量,因此您无法将文件作为流导入,因此您应该首先使用 php://temp
或 php://memory
将字符串欺骗为文件:
$fp = fopen("php://temp", 'r+');
fputs($fp, $csvText);
rewind($fp);
那么你使用 fgetcsv 就没有问题了:
$csv = [];
while ( ($data = fgetcsv($fp) ) !== FALSE )
$csv[] = $data;
$data
将是一个包含单个 csv 行的数组(可能包括换行符或逗号等)。
警告:php://temp 的内存限制可以通过附加 /maxmemory:NN 来控制,其中 NN 是在使用临时文件之前要保存在内存中的最大数据量,以字节为单位。 (默认为 2 MB)http://www.php.net/manual/en/wrappers.php.php
【讨论】:
这是真正正确处理字段内换行符的少数答案之一。它应该有更多的支持。 这是最好的方法!不要使用file('data.csv')
或explode(PHP_EOL, $csv)
,因为它们不能正确解析 csv 字符串中的换行符!
如何区分字段内的换行符和构成行/记录分隔符的换行符?
我猜它是通过确定换行符是否包裹在外壳中(通常是"
)并适当地处理它来做到这一点的。
这是更正确的方法,接受的答案是一种快速的方法,但不涵盖字段中的多行【参考方案3】:
方便的oneliner:
$csv = array_map('str_getcsv', file('data.csv'));
【讨论】:
多行 CSV 字段失败,不是吗? 将无法处理字段内的新行。接受的答案使用 PHP_EOL 解决了这个问题。很好,如果你没有新的线路,我想。感谢您的努力。 应该归功于这个方便的一个班轮的作者:php.net/manual/en/function.str-getcsv.php(见第一条评论) 只使用fgetcsv()
!因为file('data.csv')
不能正确解析 csv 字符串中的换行符!请参阅下面的正确答案。
@Alex 在方法secure.php.net/manual/en/function.str-getcsv.php 的文档中详细介绍了如何更改分隔符(例如,使用分号而不是逗号)以及包围和转义。所以该方法同样有效,只是您需要多挖掘一点并阅读文档。 PHP 文档写得很好,并且有很多例子。【参考方案4】:
我使用以下函数将 csv 字符串解析为关联数组
public function csvToArray($file)
$rows = array();
$headers = array();
if (file_exists($file) && is_readable($file))
$handle = fopen($file, 'r');
while (!feof($handle))
$row = fgetcsv($handle, 10240, ',', '"');
if (empty($headers))
$headers = $row;
else if (is_array($row))
array_splice($row, count($headers));
$rows[] = array_combine($headers, $row);
fclose($handle);
else
throw new Exception($file . ' doesn`t exist or is not readable.');
return $rows;
如果您的 csv 文件名为 mycsv.csv,那么您将此函数称为:
$dataArray = csvToArray(mycsv.csv);
你也可以在http://www.scriptville.in/parse-csv-data-to-array/获得这个脚本
【讨论】:
这是迄今为止最好的解决方案!由于我使用的是 Excel CSV,因此我已将此行$row = fgetcsv($handle, 10240, ',', '"');
更改为 $row = fgetcsv($handle, 10240, ';', '"');
【参考方案5】:
使用array_map
修改以前的答案。
用多行放大 CSV 数据。
$csv = array_map('str_getcsv', explode("\n", $csvData));
【讨论】:
【参考方案6】:略短的版本,没有不必要的第二个变量:
$csv = <<<'ENDLIST'
"12345","Computers","Acer","4","Varta","5.93","1","0.04","27-05-2013"
"12346","Computers","Acer","5","Decra","5.94","1","0.04","27-05-2013"
ENDLIST;
$arr = explode("\n", $csv);
foreach ($arr as &$line)
$line = str_getcsv($line);
【讨论】:
多行字段失败。【参考方案7】:如果需要 csv 列的名称,可以使用此方法
$example= array_map(function($v) $column = str_getcsv($v, ";");return array("foo" => $column[0],"bar" => $column[1]);,file('file.csv'));
【讨论】:
【参考方案8】:如果列中有回车/换行,str_getcsv 将不起作用。
试试https://github.com/synappnz/php-csv
用途:
include "csv.php";
$csv = new csv(file_get_contents("filename.csv"));
$rows = $csv->rows();
foreach ($rows as $row)
// do something with $row
【讨论】:
【参考方案9】:您可以使用此函数将 CSV 字符串转换为数组。
function csv2array(
$csv_string,
$delimiter = ",",
$skip_empty_lines = true,
$trim_fields = true,
$FirstLineTitle = false
)
$arr = array_map(
function ( $line ) use ( &$result, &$FirstLine, $delimiter, $trim_fields, $FirstLineTitle )
if ($FirstLineTitle && !$FirstLine)
$FirstLine = explode( $delimiter, $result[0] );
$lineResult = array_map(
function ( $field )
return str_replace( '!!Q!!', '"', utf8_decode( urldecode( $field ) ) );
,
$trim_fields ? array_map( 'trim', explode( $delimiter, $line ) ) : explode( $delimiter, $line )
);
return $FirstLineTitle ? array_combine( $FirstLine, $lineResult ) : $lineResult;
,
($result = preg_split(
$skip_empty_lines ? ( $trim_fields ? '/( *\R)+/s' : '/\R+/s' ) : '/\R/s',
preg_replace_callback(
'/"(.*?)"/s',
function ( $field )
return urlencode( utf8_encode( $field[1] ) );
,
$enc = preg_replace( '/(?<!")""/', '!!Q!!', $csv_string )
)
))
);
return $FirstLineTitle ? array_splice($arr, 1) : $arr;
【讨论】:
【参考方案10】:试试这个,它对我有用:
$delimiter = ",";
$enclosure = '"';
$escape = "\\" ;
$rows = array_filter(explode(PHP_EOL, $content));
$header = NULL;
$data = [];
foreach($rows as $row)
$row = str_getcsv ($row, $delimiter, $enclosure , $escape);
if(!$header)
$header = $row;
else
$data[] = array_combine($header, $row);
【讨论】:
array_combine(): 两个参数应该有相同数量的元素,我该如何纠正和检查我是否有相同的数量,它们是 2 个关联数组以上是关于PHP CSV字符串到数组的主要内容,如果未能解决你的问题,请参考以下文章