如何使用PHP解析CSV文件

smi*_*ith 123 php csv fgetcsv

假设我有一个.csv包含以下内容的文件:

 "text, with commas","another text",123,"text",5; 
 "some    without commas","another text",123,"text";
 "some text with  commas or no",,123,"text"; 
Run Code Online (Sandbox Code Playgroud)

如何通过PHP解析内容?

the*_*imp 170

只需使用该函数解析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);
}
Run Code Online (Sandbox Code Playgroud)

  • 应该注意的是,此功能无法正确处理CSV中的引号.具体来说,它不能处理维基百科中的这个例子:https://en.wikipedia.org/wiki/Comma-separated_values#Example有一个开放的bug,但它已被关闭为"不会修复"https :?//bugs.php.net/bug.php ID = 50686 (20认同)
  • 在内容中也有换行符的列上也无法正常工作 (2认同)

Ald*_*ein 122

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

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

  • 请注意,如果实际值中有任何换行符(而不是每个csv行末尾的行分隔符),则这不起作用,因为`file`函数在换行符上分割并且不知道CSV的引号用于包含字段值. (18认同)
  • @Julix使用[接受的答案](http://stackoverflow.com/a/9139210/477513).如果您知道导入的数据永远不会在单个值中包含换行符,那么这个较短的版本会很好,但是更强大的解决方案值得额外的代码行. (5认同)

小智 94

方便的一行内容将CSV文件解析为数组

$csv = array_map('str_getcsv', file('data.csv'));
Run Code Online (Sandbox Code Playgroud)

  • 你知道,给各自的作者提供学分是很好的:http://php.net/manual/en/function.str-getcsv.php#114764 (26认同)
  • 请注意,如果实际值中有任何换行符(而不是每个csv行末尾的行分隔符),则这不起作用,因为`file`函数在换行符上分割并且不知道CSV的引号用于包含字段值. (18认同)
  • 使用以下方法修复新行问题:array_map('str_getcsv',file('data.csv',FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES)); (4认同)
  • 如何使用不同的分隔符?( ; 代替 , ) (3认同)

qua*_*ian 13

刚刚发现了一种在解析时获取索引的方便方法.我的思绪被炸了.

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

来源:链接

  • @valerie 我在解析 CSV 时几乎总是需要一个索引。for 循环提供索引,无需单独的声明和增量器。 (2认同)

小智 6

我一直在寻找同样的东西,而不使用一些不受支持的 PHP 类。Excel CSV 并不总是使用引号分隔符,而是使用“”转义引号,因为该算法可能是在 80 年代或其他时期制定的。在查看 PHP.NET 评论部分中的几个 .csv 解析器后,我发现有些解析器甚至使用了回调或评估代码,但它们要么无法按需要工作,要么根本无法工作。因此,我为此编写了自己的例程,它们在最基本的 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;
     }
Run Code Online (Sandbox Code Playgroud)

...鲍勃现在可以返回他的电子表格


ack*_*ser 6

我喜欢这个

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

在我的情况下,我将通过Web服务获取一个csv,因此无需创建文件。但是,如果您需要解析文件,则只需要以字符串形式传递