2012-12-01 9 views
6

Sono nuovo a Pyparsing (e piuttosto nuovo a Python). Ho cercato di ridurre il mio problema alla forma più semplice che illustrerà cosa non va (al punto in cui probabilmente non avrei affatto bisogno di Pyparsing!)Pyparsing newbie setParseAction che modifica i token

Supponiamo di avere una stringa composta da lettere e numeri , ad esempio "b7 z4 a2 de c3". C'è sempre una lettera, ma il numero è facoltativo. Voglio analizzare questo nei suoi singoli elementi e quindi elaborarli, ma dove c'è una lettera vuota, senza numero, sarebbe utile cambiarla in modo che avesse il numero "predefinito" 1 dopo di esso. Quindi potrei elaborare ogni elemento in modo coerente. Ho pensato che avrei potuto fare questo con un setparseAction, come segue:

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) 

Purtroppo, il t.append() non fa quello che mi aspetto, che era quello di aggiungere un "1" per l'elenco dei gettoni analizzati. Invece, ottengo un errore: TypeError: l'oggetto 'str' non è richiamabile.

Probabilmente sono solo molto fico, qui, ma uno di voi esperti potrebbe dirmi chiaramente.

Grazie

Steve

risposta

4

Uno dei concetti di base per circa pyparsing è che non funziona solo con liste di stringhe, ma assembla i pezzi analizzati in un oggetto ParseResults. ParseResults è un tipo di dati ricco definito in pyparsing, a cui è possibile accedere come elenco o come dict o oggetto se vi sono token che sono stati analizzati da un ParserElement con un nome di risultati definito.

Tuttavia, mentre ParseResults è stato progettato con un facile accesso in mente, è limitato nei modi in cui può essere aggiornato. Internamente in Pyparsing, ogni espressione che corrisponde crea un piccolo oggetto ParseResults; se fa parte di un'espressione grande, quell'espressione accumula i pezzi in un ParseResults di grandi dimensioni usando l'operatore + =.

Nel tuo caso, è possibile aggiungere alle ParseResults che viene passato attraverso la creazione di un piccolo ParseResults contenente "1" e l'aggiunta a t:

t += ParseResults("1") 

Purtroppo, questo non funzionerà come un lambda - si potrebbe provare

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

Ma questo si sente un po 'troppo intelligente.

È anche possibile rivedere un po 'il parser per sfruttare la classe Optional. Pensa alla tua cifra finale come a un elemento facoltativo, per il quale puoi definire un valore predefinito da fornire nel caso in cui l'elemento sia mancante. Penso che si può definire ciò che si vuole con un semplice:

>>> 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'] 

mietitrebbia è utilizzato per ricongiungersi con le lettere e le cifre separate in stringhe, altrimenti ogni partita sarà simile ['a','2'], ['b','5'], ecc

(di norma, i rendimenti searchstring un elenco di oggetti ParseResults, che apparirebbero come un elenco di elenchi di elementi singoli. Passando i risultati di searchString a sum questo li aggiunge tutti in un solo ParseResults di stringhe.)

+0

Ah sì, questo ha perfettamente senso ora! Quando ho stampato i risultati delle analisi, sembravano una lista normale, quindi ho pensato di poter aggiungere il solito modo. Inoltre, mi sono perso il fatto che Opzionale consente un'impostazione predefinita, che fornisce una soluzione complessiva più ordinata.E si applicherà al mio programma attuale, che è un po 'più complesso della versione ridotta qui. molte grazie per il tuo aiuto .... e per Pyparsing stesso! Steve. –