2012-04-16 96 views
15

我有一个包含字段名称的第一行的CSV。示例数据是...将CSV处理为阵列,并使用列标题输入密钥

"Make","Model","Note" 
"Chevy","1500","loaded" 
"Chevy","2500","" 
"Chevy","","loaded" 

我需要我的数据格式化在键值对的数组中,其中键名是列标题。我想这将是这样的第1行:

$array = [ 
    "Make" => "Chevy", 
    "Model" => "1500", 
    "Note" => "loaded" 
]; 

...第2行...

$array = [ 
    "Make" => "Chevy", 
    "Model" => "1500", 
    "Note" => "" 
]; 

...和第3行...

$array = [ 
    "Make" => "Chevy", 
    "Model" => "", 
    "Note" => "loaded" 
]; 

我我不知道如何做到这一点,而不是静态 - 问题是与他们相关的数据列可能会改变从一个文件到下一个列重新安排,删除或添加。

你的想法是非常感谢。

+0

你可能意味着2500在第二个数组示例中 – user1899415 2013-11-07 16:05:29

回答

39
$all_rows = array(); 
$header = fgetcsv($file); 
while ($row = fgetcsv($file)) { 
    $all_rows[] = array_combine($header, $row); 
} 
print_r($all_rows); 
+0

感谢您的及时响应。尽管我最后得到了关键数据,但这很接近。在任何返回的数组中看不到任何列标题。 – 2012-04-16 20:34:56

+1

@BitBucket:如果您执行'$ all_rows'中的数据转储,则应该看到一个包含以标题数据为键的子数组的数组。 – 2012-04-16 20:39:28

+0

请注意,当您第一次创建它时,您需要运行$ header,以确保您给出没有标题虚拟数据(如“未知”)的任何列。 $ x或数组合并将有不同的长度 – Titan 2016-09-22 09:58:22

27

PHP提供了你需要内SplFileObject什么已经99.9%,可以通过从其延伸添加缺少的0.1%。在下面的例子CSVFile从它延伸:

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

foreach ($csv as $line) 
{ 
    var_dump($line); 
} 

与您的数据。例如:

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" 
} 

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; 
    } 
} 

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

编辑:

然而给出的实施例是在短重新usablity方面。相反,从SplFileObject延长它的好得多总IT:

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; 
    } 
} 

的代码相同但被封装在构造函数的细节被排除在外。这种减少允许更广泛地使用该类型,例如,与(但不仅与)上述SplFileObject

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

$csv = new KeyedArrayIterator($file); 

foreach ($csv as $line) { 
    var_dump($line); 
} 

如果现在听起来太冗长,它可再次包装再次给它一个更好的外观:

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

得益于标准装修能力TraversableIterator的第一个示例的原始构造函数代码可以仅复制100%的CSVFile

这最后此外还可以保持原有的代码,使用CSVFile迭代器完好:

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

foreach ($csv as $line) { 
    var_dump($line); 
} 

所以只是一个快速重构,让更多的代码重用。你可以免费获得KeyedArrayIterator

+1

非常不错...... – 2012-11-26 17:15:45

+0

您是否可以为了兴趣而想出一种使这个句柄无标题CSV的方法? – 2012-11-26 17:17:11

+1

这非常简单:省略'rewind'函数,并在构造函数中传递键。如果你需要更多的灵活性,我已经用一些例子把一些代码加入到了要点中,但它仍然很漂亮:https://gist.github.com/4153380 – hakre 2012-11-27 09:59:19

0

尝试使用此代码:

$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); 

感谢

2
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; 
} 
1

在这一点上我假设你已经解决了这个问题,但认为我会在解决这个建议的方式抛,可能不是最好/最优雅的解决方案,但它的确有诀窍:

$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>'; 
} 
4
$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 
} 
0

试试这个

$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); 
0

在上面添库珀的答案,而不是

$all_rows = array(); 
$header = null; 
while ($row = fgetcsv($file)) { 
    if ($header === null) { 
     $header = $row; 
     continue; 
    } 
    $all_rows[] = array_combine($header, $row); 
} 

我的代码,在一个更优雅的和有效的方式:

$all_rows = array(); 
$header = fgetcsv($file); 
while ($row = fgetcsv($file)) { 
    $all_rows[] = array_combine($header, $row); 
}