2009-01-22 10 views
6

ho già riuscito a dividere il file CSV utilizzando questa espressione regolare: "/, (=? (:? [^ \"] \ "[^ \"] \ ") (?! [^ \ "] \"))/"espressione regolare per il parsing CSV in PHP

Ma ho finito con una serie di stringhe che contengono le virgolette doppie di apertura e di fine. Ora ho bisogno di un'espressione regolare che rimuova quelle stringhe delle doppie virgolette del delimitatore.

Per quanto ne so, il formato CSV può incapsulare stringhe tra virgolette doppie e tutte le virgolette doppie che sono già parte della stringa sono raddoppiate. Per esempio:

mio "altro" gatto

diventa

"My "" altro" "cat"

Quello che fondamentalmente bisogno è una regex che andrà a sostituire tutte le sequenze di N doublequotes con una sequenza di virgolette doppie (N/2 - arrotondate per difetto).

O c'è un modo migliore? Grazie in anticipo.

risposta

21

C'è funzione per la lettura dei file CSV: fgetcsv

+10

+1 Tu sei pazzo da usare regex per CSV in PHP quando c'è una funzione integrata che fa esattamente ciò che desideri – cletus

+1

Sì. Perché vuoi re-inventare la ruota quando c'è qualcosa là fuori che è molto ben testato e che funziona per risolvere il tuo problema. – Rachel

+1

Perché forse si ottiene un'esportazione CSV da una terza parte che non cita correttamente i campi di testo e fgetcsv interpreta erroneamente la stringa 1.15 come float con il valore di 1.1499999999. Tuttavia, alla fine è stato più facile scrivere uno script rapido per correggere il file CSV e quindi usare fgetcsv: o) – frak

0

Ecco il mio rapido tentativo, anche se funzionerà solo sui confini delle parole.

preg_replace('/([\W]){2}\b/', '\1', $csv) 
4

perché vi preoccupate dividere il file con regex quando c'è la funzione fgetcsv che fa tutto il lavoro duro per voi?

È possibile passare il separatore e il delimitatore e rileverà cosa fare.

+0

Sì, semplice come il formato CSV, elaborarlo con espressioni regex è fastidiosamente scomodo. Se hai a disposizione un parser fatto apposta, usa assolutamente quello. –

2

Sono d'accordo con gli altri che hanno affermato che è necessario utilizzare la funzione fgetcsv anziché regex. Una regex può funzionare correttamente su dati CSV ben formati, ma se il CSV è malformato o corrotto, la regex fallirà silenziosamente, probabilmente restituendo risultati fasulli nel processo.

Tuttavia, la domanda riguardava specificamente la rimozione delle virgolette indesiderate dopo la divisione iniziale. La soluzione proposta (finora) è troppo ingenua e tratta solo le virgolette di escape all'interno di un campo, non i delimitatori effettivi. (So ​​che il PO non ha chiesto di quelli, ma hanno bisogno di essere rimosso, quindi perché non fare loro allo stesso come gli altri?) Ecco la mia soluzione:

$csv_field = preg_replace('/"(.|$)/', '\1', $csv_field); 

Questa espressione regolare corrisponde a un segno di virgolette seguito da qualsiasi carattere o dalla fine della stringa e sostituisce il carattere oi caratteri corrispondenti con il secondo carattere o con la stringa vuota se era lo $ corrispondente. Secondo le specifiche, i campi CSV possono contenere separatori di riga; non sembra che accada molto, ma è possibile aggiungere il modificatore 's' alla regex se necessario.

1

Per quelli di voi che non vogliono usare regex invece di fgetcsv. Ecco un esempio completo su come creare una tabella html da csv usando una regex.

$data = file_get_contents('test.csv'); 
    $pieces = explode("\n", $data); 

    $html .= "<table border='1'>\n"; 
    foreach (array_filter($pieces) as $line) { 

      $html .= "<tr>\n"; 
      $keywords = preg_split('/,(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))/', $line,-1,PREG_SPLIT_DELIM_CAPTURE); 

      foreach ($keywords as $col) { 
        $html .= "<td>".trim($col, '"')."</td>\n"; 
      } 
      $html .= "</tr>\n"; 
    } 
    $html .= "</table>\n"; 
2
preg_split('/,(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))/', $line,-1,PREG_SPLIT_DELIM_CAPTURE); 

ha problemi con "dentro di stringhe come "Toys" R" Us"

Così u dovrebbe usare al posto:

preg_split('/'.$seperator.'(?=(?:[^\"])*(?![^\"]))/', $line,-1, PREG_SPLIT_DELIM_CAPTURE); 
+0

Questo non elimina le virgolette doppie attorno alla stringa e converte le virgolette doppie (espresse come "" o \ ") all'interno della stringa. Quindi aggiungo questo codice:' array_walk ($ m, create_function ('& $ item, $ chiave ',' $ item = str_replace (array (\ '"" \ ", \' \\" \ '), \' "\", trim ($ item, \ '"\')); ')); ', dove m è la matrice risultante dell'istruzione preg_split (nota: utilizzo create_function a causa della versione php <5.3) –

+0

Questo non funziona per la linea csv con una virgola nella stringa. –