2012-02-04 30 views
60

Supponiamo che io abbia un file .csv con il seguente contenuto:come analizzare un file CSV utilizzando PHP

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

Come posso analizzare il contenuto tramite PHP?

+0

Stai fondamentalmente chiedendo se c'è un modo migliore per affrontare OOP w/parsing CSV che la scorta approccio funzione globale. Direi di riformulare la domanda, in quanto ciò non sembra un problema che analizza davvero un CSV. – quickshiftin

+0

@quickshiftin mi dispiace per quello – smith

+0

Va bene, sto solo dicendo ... Se vuoi una classe [questa] (http://code.google.com/p/parsecsv-for-php/) è OK (L'ho ottimizzato un po 'nel mio lavoro ...) – quickshiftin

risposta

88

Basta utilizzare la funzione per l'analisi di un file 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); 
} 
+13

si deve notare che questa funzione non gestisce correttamente le virgolette in CSV. Nello specifico, non può trattare questo esempio come trovato in wikipedia: https://en.wikipedia.org/wiki/Comma-separated_values#Example c'è stato un bug aperto, ma è stato chiuso come "wont fix" https : //bugs.php.net/bug.php? id = 50686 – amenthes

+7

Chi continua a modificarlo. Il collegamento al MANUALE è lì in modo che possano RTFM Non eliminarlo e aggiungere parole che non ho mai detto. Il punto di modifica è correggere gli errori. – thenetimp

2

io cercavo la stessa cosa senza usare un po 'di classe PHP supportato. Excel CSV non usa sempre i separatori delle virgolette e sfugge alle virgolette usando "" perché l'algoritmo è stato probabilmente reso indietro agli anni '80 o qualcosa del genere. Dopo aver esaminato diversi parser .csv nella sezione commenti su PHP.NET, ho visto quelli che utilizzavano anche callback o codice eval'd e non funzionavano come necessario o semplicemente non funzionavano affatto. Quindi, ho scritto le mie routine per questo e funzionano nella configurazione PHP più semplice. Le chiavi dell'array possono essere numeriche o nominate come i campi dati nella riga di intestazione. Spero che questo ti aiuti.

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: [email protected] 
    // 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: [email protected] 
     // 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 ora può tornare ai suoi speadsheets

86

risposta Un po 'più corta dal PHP >= 5.3.0:

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

Penso che dovrebbe essere '$ data []', giusto? – Phoenix

+1

@Phoenix, grazie, risolto. – Aldekein

+4

risposta migliore IMO, grazie :) –

3

Amo questo

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

nel mio caso ho otterrò un csv attraverso i servizi web, quindi in questo modo non ho bisogno di creare il file. Ma se avete bisogno di parser con un file, è necessario solo per passare come stringa

56

Handy uno di linea per analizzare un file CSV in un array

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

, apprezzo l'unico rivestimento –

+12

Nota che questo non funziona se hai delle nuove righe nei valori attuali (non i delimitatori di riga alla fine di ogni riga csv), perché la funzione 'file' si divide su newline e non è consapevole delle virgolette utilizzate da CSV per contenere i valori dei campi. –

+2

Come utilizzare un delimitatore diverso? (; invece di,) – sdd

3

appena scoperto un modo pratico per ottenere un indice durante l'analisi . La mia mente era esplosa.

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

Fonte

: link

+0

Il nostro server aveva PHP 5.2.9 e non riesco ad accedere a str_getcsv per questo motivo. fgetcsv d'altra parte risale tutta la strada per PHP 4, quindi questo è stato utile. Grazie. – Ben

Problemi correlati