2009-01-22 31 views
6

już udało się podzielić plik CSV przy użyciu tego wyrażenia regularnego: "/, (= (?:? [^ \"] \ "[^ \"] \ ") (?! [^ \ "] \"))/"Wyrażenie regularne do analizowania CSV w PHP

Ale skończyło się na tablicy ciągów, które zawierają podwójne i otwarte cudzysłowy. Teraz potrzebuję wyrażeń regularnych, które usuwają te łańcuchy podwójnych cudzysłowów separatora.

O ile mi wiadomo, format CSV może hermetyzować ciągi w podwójnych cudzysłowach, a wszystkie podwójne cudzysłowy, które są już częścią ciągu, są podwojone. Na przykład:

Mój "drugi" kot

staje

"My "" inny", "kot"

Co ja w zasadzie potrzebne jest regex, który zastąpi wszystkie sekwencje N doublequotes z sekwencja podwójnych cudzysłowów (N/2 - zaokrąglone w dół).

A może jest lepszy sposób? Z góry dzięki.

Odpowiedz

21

Istnieje funkcja odczytu plików csv: fgetcsv

+10

+1 Jesteś szalony, aby użyć wyrażenia regularnego dla CSV w PHP, gdy jest wbudowana funkcja, która robi dokładnie to, czego potrzebujesz – cletus

+1

Tak, dlaczego chcesz ponownie wymyślić koło, gdy jest coś, co jest bardzo dobrze przetestowane, a które działa by rozwiązać twój problem. – Rachel

+1

Ponieważ możesz uzyskać eksport CSV od strony trzeciej, która nie cytuje poprawnie pól tekstowych, a fgetcsv nieprawidłowo interpretuje ciąg 1.15 jako zmienną o wartości 1,1499999999. W końcu jednak łatwiej było napisać szybki skrypt, aby naprawić plik CSV, a następnie użyć fgetcsv: o) – frak

0

Oto moja krótka próba, choć zadziała tylko na granicach słów.

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

Dlaczego przeszkadza dzielenie pliku z regex, gdy istnieje funkcja fgetcsv który wykonuje całą ciężką pracę dla Ciebie?

Można przekazać separator i ogranicznik, aby wykryć, co należy zrobić.

+0

Tak, tak proste jak format CSV, przetwarzanie go z wyrażeń regularnych jest irytująco niezręczne. Jeśli masz specjalnie przygotowany analizator składni, użyj go. –

2

Zgadzam się z innymi, którzy powiedzieli, że powinieneś używać funkcji fgetcsv zamiast wyrażeń regularnych. Wyrażenie regularne może działać poprawnie na dobrze sformułowanych danych CSV, ale jeśli plik CSV jest zniekształcony lub uszkodzony, regex zakończy się niepowodzeniem, prawdopodobnie zwracając fałszywe wyniki w procesie.

Pytanie dotyczyło jednak usuwania niepotrzebnych cudzysłowów po początkowym rozbiciu. Proponowane rozwiązanie (do tej pory) jest zbyt naiwne i zadaje tylko ukryte cudzysłowy wewnątrz pola, a nie faktyczne ograniczniki. (Wiem, że PO nie zapytać o nich, ale one muszą być usunięte, więc dlaczego nie zrobić je w taki sam jak inni?) Oto moje rozwiązanie:

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

Ten regex dopasowuje cudzysłów po którym następuje dowolny znak lub koniec łańcucha, i zastępuje dopasowany znak (y) drugim znakiem lub pustym łańcuchem, jeśli pasuje do siebie. Według specyfikacji, pola CSV mogą zawierać separatory linii; to nie wydaje się być dużo, ale jeśli chcesz, możesz dodać modyfikator 's' do regex.

1

Dla tych z was, którzy nie będą używać wyrażeń regularnych zamiast fgetcsv. Oto pełny przykład tworzenia tabeli html z csv za pomocą wyrażenia regularnego.

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

ma problemy z "wewnątrz ciągów jak "Toys" R" Us”

Tak powinno u używać zamiast:

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

To nie usuwa podwójnych cudzysłowów wokół ciągu znaków i nie konwertuje podwójnych cudzysłowów (wyrażonych jako "" lub \ ") w ciągu znaków, więc dodaję ten kod:' array_walk ($ m, create_function ('& $ item, $ key ',' $ item = str_replace (array (\ '"" \ ", \' \\" \ '), \' "\ ', trim ($ item, \'" \ '));')); ', gdzie m jest wynikową tablicą instrukcji preg_split (uwaga: Używam create_function z powodu wersji php może <5.3) –

+0

To nie działa dla linii csv z przecinkiem w łańcuchu. –