2012-12-01 13 views
6

Jestem nowy w Pyparsing (i całkiem nowy w Pythonie). Próbowałem ograniczyć mój problem do najprostszej formy, która zilustruje, co dzieje się nie tak (do punktu, w którym prawdopodobnie nie będę potrzebował Pyparowania!)Pyparsing newbie setParseAction modyfikujące tokeny

Załóżmy, że mam ciąg złożony z liter i cyfr , na przykład "b7 z4 a2 de c3". Zawsze jest litera, ale liczba jest opcjonalna. Chcę przetworzyć to na poszczególne elementy, a następnie je przetwarzać, ale tam, gdzie jest pusta litera, bez numeru, byłoby wygodniej zmienić ją tak, aby miała po niej "domyślną" cyfrę 1. Wtedy mógłbym przetwarzać każdy element w spójny sposób. Myślałem, że mogę robić to z setparseAction, co następuje:

from pyparsing import * 
teststring = "a2 b5 c9 d e z" 
expected_letter = Word("ABCDEFGabcdefgzZxy", exact=1) 
expected_number = Word(nums) 
letter_and_number = expected_letter + expected_number 
bare_letter = expected_letter 
bare_letter.setParseAction(lambda s,l,t: t.append("1")) 
elements = letter_and_number | bare_letter 
line = OneOrMore(elements) 
print line.parseString(teststring) 

Niestety t.append() nie robi tego, co ja oczekuję, która miała dodać „1” na liście analizowane żetony. Zamiast tego pojawia się błąd: TypeError: obiekt "str" ​​nie jest wywoływalny.

Prawdopodobnie po prostu jestem naprawdę gęsty, ale może jeden z was, eksperci, wyprostuje mnie.

Dzięki

Steve

Odpowiedz

4

Jednym z podstawowych pojęć, aby uzyskać około pyparsing jest to, że nie działa tylko z listami strun, ale montuje przeanalizowane kawałki do obiektu ParseResults. ParseResults to bogaty typ danych zdefiniowany w pyparsingu, do którego można uzyskać dostęp jako listę lub jako dict lub obiekt, jeśli istnieją tokeny, które zostały sparsowane z ParserElement z określoną nazwą wyników.

Mimo że ParseResults został zaprojektowany z myślą o łatwym dostępie, jest ograniczony pod względem sposobów jego aktualizacji. Wewnętrznie w pyparsingu, każde dopasowane wyrażenie tworzy mały obiekt ParseResults; jeśli jest to część dużego wyrażenia, to wyrażenie gromadzi kawałki w duże ParseResults za pomocą operatora + =.

W twoim przypadku można dołączyć do ParseResults że przepuszcza się przez tworzenie małych ParseResults zawierające „1” i dodanie go do t:

t += ParseResults("1") 

Niestety, to nie będzie działać jak lambda - możesz spróbować:

lambda s,l,t: t.__iadd__(ParseResults("1")) 

Ale to wydaje się trochę zbyt sprytne.

Możesz także przemyśleć nieco swój parser, aby skorzystać z klasy Opcjonalnie. Pomyśl o swojej końcowej cyfrze jako elemencie opcjonalnym, dla której możesz zdefiniować wartość domyślną w przypadku braku elementu. Myślę, że można określić to, co chcesz z tylko:

>>> letter = Word(alphas,exact=1) 
>>> digit = Word(nums,exact=1) 
>>> teststring= "a2 b5 c9 d e z" 
>>> letter_and_digit = Combine(letter + Optional(digit, default="1")) 
>>> print (sum(letter_and_digit.searchString(teststring))) 
['a2', 'b5', 'c9', 'd1', 'e1', 'z1'] 

Kombajny służy do dołączyć oddzielne litery i cyfry na ciągi, w przeciwnym razie każdy mecz wyglądałby ['a','2'], ['b','5'] itp

(normalnie searchString zwrotów listę obiektów ParseResults, które wyglądałyby jak lista list pojedynczych elementów. Przekazując wyniki searchString do sum dodaje je wszystkie do jednego ciągu ParseResults ciągów.)

+0

Ach tak, teraz ma to sens! Kiedy wydrukowałem wyniki analizy, wyglądały jak normalna lista, więc pomyślałem, że mogę dołączyć w zwykły sposób. Brakowało mi również faktu, że Opcjonalnie pozwala na ustawienie domyślne, które zapewnia lepsze ogólne rozwiązanie.I będzie to dotyczyło mojego aktualnego programu, który jest nieco bardziej skomplikowany niż wersja tutaj obnażona. bardzo dziękuję za pomoc .... i za samą Pyparsing! Steve. –