【问题标题】:How to parse a CSV file using PHP [duplicate]如何使用 PHP 解析 CSV 文件 [重复]
【发布时间】:2012-02-26 16:38:58
【问题描述】:

假设我有一个.csv 文件,其内容如下:

 "text, with commas","another text",123,"text",5; 
 "some    without commas","another text",123,"text";
 "some text with  commas or no",,123,"text"; 

如何通过 PHP 解析内容?

【问题讨论】:

  • 您基本上是在问是否有比股票全局函数方法更好的 OOP 方法来处理 CSV 解析。我想说改写这个问题,因为这听起来不像是解析 CSV 的问题。
  • @quickshiftin 对此感到抱歉
  • 没关系,我只是说......如果你想要一个课程this one 没问题(我在我的工作中对其进行了一些调整......)

标签: php csv fgetcsv


【解决方案1】:

只需使用解析CSV文件的功能

http://php.net/manual/en/function.fgetcsv.php

$row = 1;
if (($handle = fopen("test.csv", "r")) !== FALSE) {
  while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
    $num = count($data);
    echo "<p> $num fields in line $row: <br /></p>\n";
    $row++;
    for ($c=0; $c < $num; $c++) {
        echo $data[$c] . "<br />\n";
    }
  }
  fclose($handle);
}

【讨论】:

【解决方案2】:

PHP >= 5.3.0以来的答案有点短:

    $csvFile = file('../somefile.csv');
    $data = [];
    foreach ($csvFile as $line) {
        $data[] = str_getcsv($line);
    }

【讨论】:

  • 请注意,如果您在实际值中有任何换行符(不是每个 csv 行末尾的行分隔符),这将不起作用,因为 file 函数在换行符上拆分并且不是不知道 CSV 用于包含字段值的引号。
  • @JordanLev 那么你有什么推荐的呢?
  • @Julix 使用 the accepted answer 。如果您知道导入的数据在单个值中永远不会有换行符,那么这个较短的版本会很好,但是更强大的解决方案值得额外的代码行。
  • 我最终在保存为 CSV 并在读取时解码之前进行了编码 - php.net/rawurlencode - 确保没有换行符,对吧? - 还是完全松动它们(URL 编码中可以有换行符吗?)
  • 这个答案完全适用于换行并使用 php 文件功能的魔力。谢谢
【解决方案3】:

一个方便的衬垫将 CSV 文件解析成一个数组

$csv = array_map('str_getcsv', file('data.csv'));

【讨论】:

  • 请注意,如果您在实际值中有任何换行符(不是每个 csv 行末尾的行分隔符),这将不起作用,因为 file 函数在换行符上拆分并且不是不知道 CSV 用于包含字段值的引号。
  • 如何使用不同的分隔符? ( ; 而不是 , )
  • 使用以下方法解决换行问题:array_map('str_getcsv', file('data.csv' , FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES));
  • 你知道,很高兴给各自的作者致谢:php.net/manual/en/function.str-getcsv.php#114764
  • @Maxim Kovalevsky,如何跳过标题或第一行
【解决方案4】:

刚刚发现了一种在解析时获取索引的便捷方法。我的心被炸毁了。

$handle = fopen("test.csv", "r");
for ($i = 0; $row = fgetcsv($handle ); ++$i) {
    // Do something will $row array
}
fclose($handle);

来源:link

【讨论】:

  • 我们的服务器有 PHP 5.2.9,因此我无法访问 str_getcsv。另一方面,fgetcsv 可以追溯到 PHP 4,所以这很有帮助。谢谢。
  • 只是想知道为什么使用 for 循环而不是 while 循环?
  • @valerie 我在解析 CSV 时几乎总是需要索引。 for 循环提供了没有单独声明和增量器的索引。
【解决方案5】:

我喜欢这个

$data = str_getcsv($CsvString, "\n"); //parse the rows
foreach ($data as &$row) {
    $row = str_getcsv($row, "; or , or whatever you want"); //parse the items in rows 
    $this->debug($row);
}

在我的情况下,我将通过 Web 服务获取 csv,因此我不需要创建文件。但是如果你需要解析一个文件,它只需要作为字符串传递

【讨论】:

  • 这对我来说不能正常工作。例如,这个:aaa,bbb,"ccc\nddd",eee 被解析为两行(而不是所需的一行)而不是一行。当" 出现在字段内时(而不是在其开头或结尾),它似乎未被识别为外壳。所以$data = str_getcsv(..) 可以换成$data = explode(..),我猜这样效率更高,也能更好地传达意图……
【解决方案6】:

我一直在寻找同样的东西,但没有使用一些不受支持的 PHP 类。 Excel CSV 并不总是使用引号分隔符,而是使用 "" 转义引号,因为该算法可能是在 80 年代或其他时间制作的。在查看了 PHP.NET 的 cmets 部分中的几个 .csv 解析器之后,我看到了一些甚至使用回调或 eval 代码的解析器,它们要么无法正常工作,要么根本无法正常工作。因此,我为此编写了自己的例程,它们在最基本的 PHP 配置中工作。数组键可以是数字或命名为标题行中给出的字段。希望这会有所帮助。

    function SW_ImplodeCSV(array $rows, $headerrow=true, $mode='EXCEL', $fmt='2D_FIELDNAME_ARRAY')
    // SW_ImplodeCSV - returns 2D array as string of csv(MS Excel .CSV supported)
    // AUTHOR: tgearin2@gmail.com
    // RELEASED: 9/21/13 BETA
      { $r=1; $row=array(); $fields=array(); $csv="";
        $escapes=array('\r', '\n', '\t', '\\', '\"');  //two byte escape codes
        $escapes2=array("\r", "\n", "\t", "\\", "\""); //actual code

        if($mode=='EXCEL')// escape code = ""
         { $delim=','; $enclos='"'; $rowbr="\r\n"; }
        else //mode=STANDARD all fields enclosed
           { $delim=','; $enclos='"'; $rowbr="\r\n"; }

          $csv=""; $i=-1; $i2=0; $imax=count($rows);

          while( $i < $imax )
          {
            // get field names
            if($i == -1)
             { $row=$rows[0];
               if($fmt=='2D_FIELDNAME_ARRAY')
                { $i2=0; $i2max=count($row);
                  while( list($k, $v) = each($row) )
                   { $fields[$i2]=$k;
                     $i2++;
                   }
                }
               else //if($fmt='2D_NUMBERED_ARRAY')
                { $i2=0; $i2max=(count($rows[0]));
                  while($i2<$i2max)
                   { $fields[$i2]=$i2;
                     $i2++;
                   }
                }

               if($headerrow==true) { $row=$fields; }
               else                 { $i=0; $row=$rows[0];}
             }
            else
             { $row=$rows[$i];
             }
    
            $i2=0;  $i2max=count($row); 
            while($i2 < $i2max)// numeric loop (order really matters here)
            //while( list($k, $v) = each($row) )
             { if($i2 != 0) $csv=$csv.$delim;

               $v=$row[$fields[$i2]];

               if($mode=='EXCEL') //EXCEL 2quote escapes
                    { $newv = '"'.(str_replace('"', '""', $v)).'"'; }
               else  //STANDARD
                    { $newv = '"'.(str_replace($escapes2, $escapes, $v)).'"'; }
               $csv=$csv.$newv;
               $i2++;
             }

            $csv=$csv."\r\n";

            $i++;
          }

         return $csv;
       }

    function SW_ExplodeCSV($csv, $headerrow=true, $mode='EXCEL', $fmt='2D_FIELDNAME_ARRAY')
     { // SW_ExplodeCSV - parses CSV into 2D array(MS Excel .CSV supported)
       // AUTHOR: tgearin2@gmail.com
       // RELEASED: 9/21/13 BETA
       //SWMessage("SW_ExplodeCSV() - CALLED HERE -");
       $rows=array(); $row=array(); $fields=array();// rows = array of arrays

       //escape code = '\'
       $escapes=array('\r', '\n', '\t', '\\', '\"');  //two byte escape codes
       $escapes2=array("\r", "\n", "\t", "\\", "\""); //actual code

       if($mode=='EXCEL')
        {// escape code = ""
          $delim=','; $enclos='"'; $esc_enclos='""'; $rowbr="\r\n";
        }
       else //mode=STANDARD 
        {// all fields enclosed
          $delim=','; $enclos='"'; $rowbr="\r\n";
        }

       $indxf=0; $indxl=0; $encindxf=0; $encindxl=0; $enc=0; $enc1=0; $enc2=0; $brk1=0; $rowindxf=0; $rowindxl=0; $encflg=0;
       $rowcnt=0; $colcnt=0; $rowflg=0; $colflg=0; $cell="";
       $headerflg=0; $quotedflg=0;
       $i=0; $i2=0; $imax=strlen($csv);   

       while($indxf < $imax)
         {
           //find first *possible* cell delimiters
           $indxl=strpos($csv, $delim, $indxf);  if($indxl===false) { $indxl=$imax; }
           $encindxf=strpos($csv, $enclos, $indxf); if($encindxf===false) { $encindxf=$imax; }//first open quote
           $rowindxl=strpos($csv, $rowbr, $indxf); if($rowindxl===false) { $rowindxl=$imax; }

           if(($encindxf>$indxl)||($encindxf>$rowindxl))
            { $quoteflg=0; $encindxf=$imax; $encindxl=$imax;
              if($rowindxl<$indxl) { $indxl=$rowindxl; $rowflg=1; }
            }
           else 
            { //find cell enclosure area (and real cell delimiter)
              $quoteflg=1;
              $enc=$encindxf; 
              while($enc<$indxl) //$enc = next open quote
               {// loop till unquoted delim. is found
                 $enc=strpos($csv, $enclos, $enc+1); if($enc===false) { $enc=$imax; }//close quote
                 $encindxl=$enc; //last close quote
                 $indxl=strpos($csv, $delim, $enc+1); if($indxl===false)  { $indxl=$imax; }//last delim.
                 $enc=strpos($csv, $enclos, $enc+1); if($enc===false) { $enc=$imax; }//open quote
                 if(($indxl==$imax)||($enc==$imax)) break;
               }
              $rowindxl=strpos($csv, $rowbr, $enc+1); if($rowindxl===false) { $rowindxl=$imax; }
              if($rowindxl<$indxl) { $indxl=$rowindxl; $rowflg=1; }
            }

           if($quoteflg==0)
            { //no enclosured content - take as is
              $colflg=1;
              //get cell 
             // $cell=substr($csv, $indxf, ($indxl-$indxf)-1);
              $cell=substr($csv, $indxf, ($indxl-$indxf));
            }
           else// if($rowindxl > $encindxf)
            { // cell enclosed
              $colflg=1;
     
             //get cell - decode cell content
              $cell=substr($csv, $encindxf+1, ($encindxl-$encindxf)-1);

              if($mode=='EXCEL') //remove EXCEL 2quote escapes
                { $cell=str_replace($esc_enclos, $enclos, $cell);
                }
              else //remove STANDARD esc. sceme
                { $cell=str_replace($escapes, $escapes2, $cell);
                }
            }

           if($colflg)
            {// read cell into array
              if( ($fmt=='2D_FIELDNAME_ARRAY') && ($headerflg==1) )
               { $row[$fields[$colcnt]]=$cell; }
              else if(($fmt=='2D_NUMBERED_ARRAY')||($headerflg==0))
               { $row[$colcnt]=$cell; } //$rows[$rowcnt][$colcnt] = $cell;

              $colcnt++; $colflg=0; $cell="";
              $indxf=$indxl+1;//strlen($delim);
            }
           if($rowflg)
            {// read row into big array
              if(($headerrow) && ($headerflg==0))
                {  $fields=$row;
                   $row=array();
                   $headerflg=1;
                }
              else
                { $rows[$rowcnt]=$row;
                  $row=array();
                  $rowcnt++; 
                }
               $colcnt=0; $rowflg=0; $cell="";
               $rowindxf=$rowindxl+2;//strlen($rowbr);
               $indxf=$rowindxf;
            }

           $i++;
           //SWMessage("SW_ExplodeCSV() - colcnt = ".$colcnt."   rowcnt = ".$rowcnt."   indxf = ".$indxf."   indxl = ".$indxl."   rowindxf = ".$rowindxf);
           //if($i>20) break;
         }

       return $rows;
     }

...bob 现在可以回到他的电子表格

【讨论】:

    猜你喜欢
    • 2018-07-28
    • 2011-06-12
    • 2013-02-19
    • 1970-01-01
    • 2014-03-08
    • 1970-01-01
    • 2014-07-08
    相关资源
    最近更新 更多