使用列标题将CSV处理为数组

Bit*_*ket 21 php csv arrays heading

我有一个CSV,第一行包含字段名称.示例数据是......

"Make","Model","Note"
"Chevy","1500","loaded"
"Chevy","2500",""
"Chevy","","loaded"
Run Code Online (Sandbox Code Playgroud)

我需要在键值对数组中格式化我的数据,其中键名是列标题.我猜对于第1行它会是这样的:

$array = [
    "Make" => "Chevy",
    "Model" => "1500",
    "Note" => "loaded"
];
Run Code Online (Sandbox Code Playgroud)

......排2 ...

$array = [
    "Make" => "Chevy",
    "Model" => "1500",
    "Note" => ""
];
Run Code Online (Sandbox Code Playgroud)

......和第3行......

$array = [
    "Make" => "Chevy",
    "Model" => "",
    "Note" => "loaded"
];
Run Code Online (Sandbox Code Playgroud)

我不确定除了静态之外该怎么做 - 问题是带有相关数据的列可能会从一个文件更改为下一个...重新排列,删除或添加的列.

你的想法非常感谢.

Tim*_*per 48

$all_rows = array();
$header = fgetcsv($file);
while ($row = fgetcsv($file)) {
  $all_rows[] = array_combine($header, $row);
}
Run Code Online (Sandbox Code Playgroud)
print_r($all_rows);
Run Code Online (Sandbox Code Playgroud)


hak*_*kre 32

PHP提供了99.9%的内容SplFileObject,你可以通过扩展来添加缺少的0.1%.在以下示例中CSVFile从它扩展:

$csv = new CSVFile('../data/test.csv');

foreach ($csv as $line)
{
    var_dump($line);
}
Run Code Online (Sandbox Code Playgroud)

使用您的示例数据:

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"
}
Run Code Online (Sandbox Code Playgroud)

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果你这样做,细节很好地封装起来.此外,它更容易处理current()函数内部的错误(例如计数不匹配),因此使用数据的代码不需要处理它.

编辑:

然而,给出的例子在可重用性方面很短.不是从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;
    }
}
Run Code Online (Sandbox Code Playgroud)

代码是相同的,但是在构造函数中封装的细节被省略了.这种减少允许更广泛地使用类型,例如使用(但不仅仅是)所述SplFileObject:

$file = new SplFileObject('../data/test.csv');
$file->setFlags($file::READ_CSV);

$csv = new KeyedArrayIterator($file);

foreach ($csv as $line) {
    var_dump($line);
}
Run Code Online (Sandbox Code Playgroud)

如果现在听起来过于冗长,那么它又可以被包裹起来再给它一个更好的外观:

class CSVFile extends KeyedArrayIterator
{
    /**
     * @param string $file
     */
    public function __construct($file)
    {
        parent::__construct(new SplFileObject($file));
        $this->setFlags(SplFileObject::READ_CSV);
    }
}
Run Code Online (Sandbox Code Playgroud)

由于TraversableIterator的标准装饰能力,CSVFile的第一个示例中的原始构造函数代码可以100%复制.

这最后除了还允许保留原来的代码使用CSVFile迭代器完好:

$csv = new CSVFile('../data/test.csv');

foreach ($csv as $line) {
    var_dump($line);
}
Run Code Online (Sandbox Code Playgroud)

因此,只需快速重构即可实现更多的代码重用.你可以免费获得KeyedArrayIterator.


Waq*_*ary 6

$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
}
Run Code Online (Sandbox Code Playgroud)