2009-01-30 9 views
10

Piszę narzędzie Python, które musi przeanalizować duży, regularnie aktualizowany plik CSV, którego nie kontroluję. Narzędzie musi działać na serwerze z dostępnym tylko Pythonem 2.4. Plik CSV w ogóle nie cytuje wartości pól, ale Python 2.4 version of the csv library nie wydaje mi się, aby wyłączyć cytowanie, pozwala mi tylko ustawić znak cudzysłowu (dialect.quotechar = '"' lub cokolwiek innego). Jeśli spróbuję ustawić znak cudzysłowu na None lub pusty łańcuch, pojawia się błąd.Jak wyłączyć cudzysłowy w czytniku CSV Python 2.4?

Mogę to obejść, ustawiając dialect.quotechar na jakiś "rzadki" znak, ale jest to kruche, ponieważ nie ma znaków ASCII, które mogę absolutnie zagwarantować, nie pojawią się w wartościach pól (z wyjątkiem ogranicznika, ale jeśli Ustawiam dialect.quotechar = dialect.delimiter, rzeczy idą w przewidywalny sposób.

Jeśli ustawię dialect.quoting na csv.QUOTE_NONE, czytnik CSV uszanuje to i nie interpretuje żadnego znaku jako znaku cudzysłowu. Czy istnieje sposób na skopiowanie tego zachowania w Pythonie 2.4?

UPDATE: Dzięki Tryptyk i Mark Roddy za pomoc w zmniejszeniu problemu. Oto najprostszy-case demonstracji:

>>> import csv 
>>> import StringIO 
>>> data = """ 
... 1,2,3,4,"5 
... 1,2,3,4,5 
... """ 
>>> reader = csv.reader(StringIO.StringIO(data)) 
>>> for i in reader: print i 
... 
[] 
Traceback (most recent call last): 
    File "<stdin>", line 1, in ? 
_csv.Error: newline inside string 

Problem występuje tylko wtedy, gdy pojawia się pojedynczy znak cudzysłów w ostatnim kolumnie rzędu . Niestety ta sytuacja istnieje w moim zbiorze danych. Zaakceptowałem rozwiązanie Tanja: ręcznie przypisz niedrukowaną postać ("\x07" lub BEL) jako cytację. To jest hacky, ale działa, i jeszcze nie widziałem innego rozwiązania, które to robi. Oto demo rozwiązania w akcji:

>>> import csv 
>>> import StringIO 
>>> class MyDialect(csv.Dialect): 
...  quotechar = '\x07' 
...  delimiter = ',' 
...  lineterminator = '\n' 
...  doublequote = False 
...  skipinitialspace = False 
...  quoting = csv.QUOTE_NONE 
...  escapechar = '\\' 
... 
>>> dialect = MyDialect() 
>>> data = """ 
... 1,2,3,4,"5 
... 1,2,3,4,5 
... """ 
>>> reader = csv.reader(StringIO.StringIO(data), dialect=dialect) 
>>> for i in reader: print i 
... 
[] 
['1', '2', '3', '4', '"5'] 
['1', '2', '3', '4', '5'] 

W Pythonie 2.5+ ustawienie powołując się csv.QUOTE_NONE byłaby wystarczająca, a wartość quotechar byłby wtedy znaczenia. (W rzeczywistości uzyskuję swój początkowy dialekt przez csv.Sniffer, a następnie pomijam wartość metecharną, a nie podklasując csv.Dialect, ale nie chcę, żeby to było odwrócenie uwagi od prawdziwego problemu, powyższe dwie sesje pokazują, że Sniffer nie jest problem.)

Odpowiedz

12

Nie wiem, czy Python chciałby/pozwoliłby na to, ale mógłbyś użyć niewydrukowanego kodu ASCII, takiego jak BEL lub BS (backspace). Te uważam za niezwykle rzadkie.

+0

Wow, dobry pomysł. Ustawienie csv.quotechar = '\ x07' (BEL) wydaje się zdziałać. Nie mogę sobie wyobrazić, w jaki sposób dostaną to do swoich danych CSV. –

+1

Haha - fajny hack. :-) – cdleary

+0

Fajny, hacktastyczny. – Kiv

3

Próbowałem kilku przykładów przy użyciu Pythona 2.4.3 i wydawało się, że jest wystarczająco inteligentny, aby wykryć, że pola były niecytowane.

Wiem, że już zaakceptowałeś (nieco hackowatą) odpowiedź, ale czy próbowałeś samemu zostawić wartość reader.dialect.quotechar? Co się stanie, jeśli to zrobisz?

Czy istnieje szansa, że ​​uzyskamy przykładowy sygnał wejściowy?

+0

Nadal jestem zainteresowany mniej hackowskim podejściem, jeśli takie istnieje. Mogę pobrać wkrótce próbki danych wejściowych. Dialekt, którego używam, jest generowany przez obiekt csv.Sniffer (muszę być możliwie jak najbardziej odporny na zmiany formatu). Jeśli zostawiam polecenie samemu, wydaje się domyślnie podwójnie cytować. " –

0

+1 dla Tryptyku

potwierdzenie, że csv.reader automatycznie obsługuje plików csv z cytatami OUT:

>>> import StringIO 
>>> import csv 
>>> data=""" 
... 1,2,3,4,5 
... 1,2,3,4,5 
... 1,2,3,4,5 
... """ 
>>> reader=csv.reader(StringIO.StringIO(data)) 
>>> for i in reader: 
...  print i 
... 
[] 
['1', '2', '3', '4', '5'] 
['1', '2', '3', '4', '5'] 
['1', '2', '3', '4', '5'] 
+0

To naprawdę nie jest odpowiedni test, ponieważ bez względu na to, co jest ustawione na quotechar, cytowanie jest opcjonalne, może obsłużyć niecytowane pola po prostu dobrze. jest, gdy pojawia się zapytanie w danych i najwyraźniej tylko wtedy, gdy pojawia się w ostatniej kolumnie. Dziękuję, że naciskasz, aby go zawęzić. –

Powiązane problemy