php 将 CSV 处理为带有键列标题的数组
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10181054/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Process CSV Into Array With Column Headings For Key
提问by Bit Bucket
I have a CSV with the first row containing the field names. Example data is...
我有一个 CSV,第一行包含字段名称。示例数据是...
"Make","Model","Note"
"Chevy","1500","loaded"
"Chevy","2500",""
"Chevy","","loaded"
I need my data formatted in an array of key-value pairs where the key name is the column heading. I guess it would something like this for row 1:
我需要将数据格式化为键值对数组,其中键名是列标题。我想第 1 行会是这样的:
$array = [
"Make" => "Chevy",
"Model" => "1500",
"Note" => "loaded"
];
...row 2...
...第 2 行...
$array = [
"Make" => "Chevy",
"Model" => "1500",
"Note" => ""
];
...and row 3...
...和第 3 行...
$array = [
"Make" => "Chevy",
"Model" => "",
"Note" => "loaded"
];
I'm not sure how to do this other than statically - problem is the columns with their associated data could change from one file to the next... columns rearranged, dropped, or added.
除了静态之外,我不知道如何做到这一点 - 问题是带有关联数据的列可能会从一个文件更改为下一个文件...重新排列、删除或添加的列。
You ideas are much appreciated.
非常感谢您的想法。
回答by Tim Cooper
$all_rows = array();
$header = fgetcsv($file);
while ($row = fgetcsv($file)) {
$all_rows[] = array_combine($header, $row);
}
print_r($all_rows);
回答by hakre
PHP offers already 99,9% of what you need within SplFileObject, you add the missing 0,1% by extending from it. In the following example CSVFileextends from it:
PHP 已经提供了您需要的 99.9% 的内容SplFileObject,您可以通过从它扩展来添加缺少的 0.1%。在以下示例中,CSVFile从它扩展:
$csv = new CSVFile('../data/test.csv');
foreach ($csv as $line)
{
var_dump($line);
}
With your example data:
使用您的示例数据:
array(3) {
["Make"]=> string(5) "Chevy"
["Model"]=> string(4) "1500"
["Note"]=> string(6) "loaded"
}
array(3) {
["Make"]=> string(5) "Chevy"
["Model"]=> string(4) "2500"
["Note"]=> string(0) ""
}
array(3) {
["Make"]=> string(5) "Chevy"
["Model"]=> string(0) ""
["Note"]=> string(6) "loaded"
}
CSVFileis defined as the following:
CSVFile定义如下:
class CSVFile extends SplFileObject
{
private $keys;
public function __construct($file)
{
parent::__construct($file);
$this->setFlags(SplFileObject::READ_CSV);
}
public function rewind()
{
parent::rewind();
$this->keys = parent::current();
parent::next();
}
public function current()
{
return array_combine($this->keys, parent::current());
}
public function getKeys()
{
return $this->keys;
}
}
If you do it this way, the details are nicely encapsulated away. Additionally it's more easy to deal with errors (e.g. count mismatch) inside the current()function so the code which makes use of the data does not need to deal with it.
如果你这样做,细节就会被很好地封装起来。此外,更容易处理current()函数内部的错误(例如计数不匹配),因此使用数据的代码不需要处理它。
Edit:
编辑:
However the example given is short in terms of re-usablity. Instead of extending from SplFileObjectit's much better to aggregate it:
然而,给出的示例在可重用性方面很短。与其从SplFileObject扩展,不如聚合它:
class KeyedArrayIterator extends IteratorIterator
{
private $keys;
public function rewind()
{
parent::rewind();
$this->keys = parent::current();
parent::next();
}
public function current()
{
return array_combine($this->keys, parent::current());
}
public function getKeys()
{
return $this->keys;
}
}
The code is identicalbut the details that were encapsulated in the constructor are left out. This reduction allows to use the type more broadly, e.g. with (but not only with) the said SplFileObject:
代码是相同的,但省略了封装在构造函数中的细节。这种减少允许更广泛地使用该类型,例如与(但不仅与)所述SplFileObject:
$file = new SplFileObject('../data/test.csv');
$file->setFlags($file::READ_CSV);
$csv = new KeyedArrayIterator($file);
foreach ($csv as $line) {
var_dump($line);
}
If that now sounds too verbose, it again can be wrapped to give it again a nicer facade:
如果现在听起来太冗长了,可以再次将其包裹起来,使其再次具有更好的外观:
class CSVFile extends KeyedArrayIterator
{
/**
* @param string $file
*/
public function __construct($file)
{
parent::__construct(new SplFileObject($file));
$this->setFlags(SplFileObject::READ_CSV);
}
}
Thanks to the standard decorating-ability of TraversableIterator, the original constructor code from the first example of CSVFilecould just be copied 100%.
由于TraversableIterator的标准装饰能力,CSVFile的第一个示例中的原始构造函数代码可以被 100% 复制。
This last addition also allows to keep the original code that usesthe CSVFileIterator intact:
这最后除了还允许保留原来的代码使用的CSVFile迭代器完好:
$csv = new CSVFile('../data/test.csv');
foreach ($csv as $line) {
var_dump($line);
}
So just a quick refactoring to allow more code-reuse. You get a KeyedArrayIteratorfor free.
所以只需快速重构以允许更多的代码重用。您可以免费获得KeyedArrayIterator。
回答by Waqas Bukhary
$csv_data = array_map('str_getcsv', file('Book.csv'));// reads the csv file in php array
$csv_header = $csv_data[0];//creates a copy of csv header array
unset($csv_data[0]);//removes the header from $csv_data since no longer needed
foreach($csv_data as $row){
$row = array_combine($csv_header, $row);// adds header to each row as key
var_dump($row);//do something here with each row
}
回答by Rupert
function processCsv($absolutePath)
{
$csv = array_map('str_getcsv', file($absolutePath));
$headers = $csv[0];
unset($csv[0]);
$rowsWithKeys = [];
foreach ($csv as $row) {
$newRow = [];
foreach ($headers as $k => $key) {
$newRow[$key] = $row[$k];
}
$rowsWithKeys[] = $newRow;
}
return $rowsWithKeys;
}
回答by Richard Porter
At this point I'm assuming you've already solved the issue but thought I'd throw in a suggested way around this, probably not the best/most elegant solution but it does the trick:
在这一点上,我假设你已经解决了这个问题,但我想我会提出一个建议的方法来解决这个问题,可能不是最好/最优雅的解决方案,但它确实有效:
$row = 1;
$array = array();
$marray = array();
$handle = fopen('file.csv', 'r');
if ($handle !== FALSE) {
while (($data = fgetcsv($handle, 0, ',')) !== FALSE) {
if ($row === 1) {
$num = count($data);
for ($i = 0; $i < $num; $i++) {
array_push($array, $data[$i]);
}
}
else {
$c = 0;
foreach ($array as $key) {
$marray[$row - 1][$key] = $data[$c];
$c++;
}
}
$row++;
}
echo '<pre>';
print_r($marray);
echo '</pre>';
}
回答by Krunal Shah
Try with this code:
尝试使用此代码:
$query = "SELECT * FROM datashep_AMS.COMPLETE_APPLICATIONS";
$export= mysql_query($query);
$first = true;
$temp = $export[0];
//echo "<pre>"; print_r($first); exit;
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename=file.csv');
header('Pragma: no-cache');
header("Expires: 0");
$outstream = fopen("php://output", "w");
foreach($export as $result)
{
if($first){
$titles = array();
foreach($temp as $key=>$val){
$titles[] = $key;
}
//print_r ($titles);exit;
fputcsv($outstream, $titles);
}
$first = false;
fputcsv($outstream, $result);
}
fclose($outstream);
Thanks
谢谢
回答by Azam Alvi
Try this
尝试这个
$csv = array_map("str_getcsv", file('file.csv', FILE_SKIP_EMPTY_LINES));
$header = array_shift($csv); // get header from array
foreach ($csv as $key => $value) {
$csv[$key] = array_combine($header, $value);
var_dump($csv[$key]['Model']);
}
var_dump($csv);
回答by Pierre Fran?ois
In the answer of Tim Cooper above, instead of
在上面 Tim Cooper 的回答中,而不是
$all_rows = array();
$header = null;
while ($row = fgetcsv($file)) {
if ($header === null) {
$header = $row;
continue;
}
$all_rows[] = array_combine($header, $row);
}
I would code, in a more elegant and efficient way:
我会以更优雅和有效的方式编码:
$all_rows = array();
$header = fgetcsv($file);
while ($row = fgetcsv($file)) {
$all_rows[] = array_combine($header, $row);
}
回答by no_php
The array_combine()function only works if header colums match the data colums otherwise an error is thrown.
所述array_combine()函数仅当头部colums匹配数据colums否则引发错误工作。

