2013-03-08 10 views
6

chcę używać Pythona czytnika CSV ale chcę pozostawić cytaty w To chcę.Czy czytnik csv Pythona może zostawić cytaty?

>>> s = '"simple|split"|test' 
>>> reader = csv.reader([s], delimiter='|', skipinitialspace=True) 
>>> reader.next() 
['"simple|split"', 'test'] 

Ale rzeczywiście dostać:

['simple|split', 'test'] 

w moim przypadku chcę cytowany ciąg znaków do przekazania dalej cytowany.

Wiem, że czytnik CSV działa zgodnie z przeznaczeniem, a mój przypadek użycia jest nadużyciem, ale czy jest jakiś sposób, aby nagiąć go do mojej woli? Czy muszę napisać własny parser napisów?

+0

Będziesz Muszę napisać własny parser. Cytaty są sposobem na ucieczkę danych, które w innym przypadku nie byłyby postrzegane jako jedna kolumna, a zatem nie są uważane za część danych wyjściowych. –

+1

W zależności od tego, jak skomplikowane są dane, możesz być w stanie oszukać i użyć czegoś okropnego, takiego jak 'filter (None, re.split (r '(". *? ") | \ |', S))' - lub w 'pyparsing' –

+0

Witam, napisałem odpowiedź, w której w rzeczywistości rozwijam to, co powiedzieli Martjin i Jon. Czy mógłbyś powiedzieć, dlaczego nie myślałeś o użyciu wyrażenia regularnego? – eyquem

Odpowiedz

3

Będziesz musiał napisać własny parser, jako części modułu, który plecami analizowania i cytaty jest po stronie C rzeczy, w szczególności parse_process_char znajduje się w Modules/_csv.c:

else if (c == dialect->quotechar && 
      dialect->quoting != QUOTE_NONE) { 
     if (dialect->doublequote) { 
      /* doublequote; " represented by "" */ 
      self->state = QUOTE_IN_QUOTED_FIELD; 
     } 
     else { 
      /* end of quote part of field */ 
      self->state = IN_FIELD; 
     } 
    } 
    else { 
     /* normal character - save in field */ 
     if (parse_add_char(self, c) < 0) 
      return -1; 
    } 

Że Sekcja "koniec cytowanej części pola" jest tym, co żartuje z podwójnego cudzysłowu. Z drugiej strony, możesz być w stanie zabić to warunkowe i odbudować kod źródłowy pythona. Jednak to nie wszystko, co można utrzymywać szczerze.

Edit: Przykro mi chodziło dodać trochę od ostatniego else przed self->state = IN_FIELD więc dodaje cytat w

+0

To całkiem ostateczna odpowiedź! Dziękuję Ci. –

+0

@HamishDowner Właściwie wpadłem na pomysł użycia modułu PyPy (Python w Pythonie) i zmodyfikowania go, aby utworzyć niestandardowy, który można umieścić w projekcie. Zamierzam trochę się z tym zabawić i zobaczyć, czy uda mi się go uruchomić, aby nie trzeba było wymyślać żadnych kół. – cwgem

+1

@HamishDowner Tak, dałem mu szansę, ale kod modułu csv PyPy, nawet będąc w pytonie, wciąż ma dużo rozproszonych importów pypowych. Niestety byłoby to trochę za dużo wysiłku. Może zajrzeć do ich [csv reader code] (https://bitbucket.org/pypy/pypy/src/5a61eff6b57fa1bfa95bd0d04e4a9421dab987ce/pypy/module/_csv/interp_reader.py) w każdym razie, jeśli potrzebujesz pomysłów na obsługę praca z parserem. – cwgem

2

Nie rozumiem, jeśli masz jasny obraz tego, co staramy się uzyskać..
Mówisz: "Wiem (...) mój przypadek użycia jest nadużyciem".
Ale nadużycie oznacza, że ​​istnieje możliwość użycia.
Jednak w twoim przypadku nie ma możliwości użycia, to co "opisałeś" jest niemożliwe, ponieważ to, co jest przekazywane do parsera CSV, musi mieć poprawny format CSV, a twoje nie.

W prawidłowym ciągu CSV większość znaków to informacje, a niektóre znaki są meta-informacjami niezbędnymi do interpretacji ciągu w celu wyodrębnienia informacji.
To, co opisujesz, to to, że chcesz, aby znaki " należały do ​​kategorii informacji i kategorii meta-informacji łącznie. To tak, jakby ktoś chciał złapać lewą ręką lewą ręką .....

Ten problem występuje z ciągiem znaków, ponieważ nie jest ciągiem pochodzącym z odczytu pliku CSV. Jest to ciąg napisany tak jak jest.
Nie można uzyskać takiego ciągu z odczytu pliku CSV, ponieważ nie można go było zapisać w pliku CSV.
przypadku zapisu do pliku CSV, '"simple|split"|test' można zapisać

  • """simple|split"""|test
    z doublequote ustawiona na True, domyślny

  • lub #"simple#|split#"|test
    z doublequote = False, escapechar = '#'

.

Jeśli chcesz, aby wyodrębnić informacje jak opisałeś, nie trzeba utworzyć parser, trzeba tylko użyć już istniejące narzędzia:

import re 

reg = re.compile('".*?"|[^|]+') 

print reg.findall('yoo|"simple|split"|test|end"pos|hu') 

wynik

['yoo', '"simple|split"', 'test', 'end"pos', 'hu'] 
Powiązane problemy