2014-12-17 10 views
5

La continuazione della mia ricerca PyParsing sta analizzando espressioni ternarie annidate (ad esempio (x == 1 ? true : (y == 10 ? 100 : 200))). Come tale, ho costruito la seguente espressione. Che, per me, sembra intuitivo. Tuttavia non ottengo corrispondenze:Analisi di espressioni ternarie nidificate

any = Word(printables) 

conditional = Forward() 
sub_exp = (conditional | any) 
conditional = Literal('(') + sub_exp + Literal('?') + sub_exp + Literal(':') + sub_exp + Literal(')') 

    for exp in conditional.scanString(block_str): 
     print exp 

Inizialmente ho pensato che il problema fosse con stampabili che consumavano tutto; Ho impostato l'excludeChars per non corrispondere allo :?)(, ma non è stato d'aiuto. L'alternativa era costruire espressioni nidificate, una per ciascuno dei blocchi "(?", "?:" e ":)". Ma questo approccio è molto complicato. Qualcuno ha qualche consiglio su come analizzare le espressioni ternarie?

UPDATE Utilizzando la risposta dal basso, ma modificato per funzionare con scanString:

Quando si utilizza scanString però, restituisce un sacco di altre partite troppo (in pratica, niente corrispondenza atomo).

lpar = Literal('(').suppress() 
rpar = Literal(')').suppress() 
any = Combine(OneOrMore(Word(printables, excludeChars='()?:') | White(' ', max=1))) 
expr = Forward() 
atom = any | Group(lpar + expr + Literal('?') + expr + Literal(':') + expr + rpar) 
expr << Literal('(') + atom + ZeroOrMore(expr) + Literal('?') + atom + ZeroOrMore(expr) + Literal(':') + atom + ZeroOrMore(expr) + Literal(')') 

for ternary_exp in expr.scanString(block_str): 
    print ternary_exp 
+1

Forse è un problema di spazio. La tua espressione corrisponde a "? (X == 1? True: (y == 10? 100: 200))" "? – Kevin

+0

No, inutilmente. Nessuna corrispondenza (e nessun errore). – JB2

+2

Si sta assegnando a 'condizionale' due volte, è quello previsto? Inoltre, definirei un segnaposto di espressione che è ciò che il tuo '(condizionale | qualsiasi)' è sopra e che può essere testato separatamente. BTW: quale delle parti che utilizzi combaciano separatamente? –

risposta

1

per questo tipo di aritmetica espressione parsing, provare a utilizzare pyparsing di integrato infixNotation (precedentemente noto come operatorPrecedence):

from pyparsing import * 

integer = Word(nums) 
variable = Word(alphas, alphanums) 
boolLiteral = oneOf("true false") 

operand = boolLiteral | variable | integer 

comparison_op = oneOf("== <= >= != < >") 
QM,COLON = map(Literal,"?:") 
expr = infixNotation(operand, 
    [ 
    (comparison_op, 2, opAssoc.LEFT), 
    ((QM,COLON), 3, opAssoc.LEFT), 
    ]) 

print expr.parseString("(x==1? true: (y == 10? 100 : 200))") 

Stampe

[[['x', '==', '1'], '?', 'true', ':', [['y', '==', '10'], '?', '100', ':', '200']]] 

infixNotation si prende cura di tutte le espressioni ricorsive, e risolve la precedenza delle operazioni e prioritario di che la precedenza utilizzando() 's.

3

Credo che il problema è duplice: gli spazi bianchi (che non è gestita bene dal any definizione), e la ricorsione (che dovrebbe usare l'operatore <<):

lpar = Literal('(').suppress() 
rpar = Literal(')').suppress() 
any = Combine(OneOrMore(Word(printables, excludeChars='()?:') | White(' ',max=1))) 
expr = Forward() 
atom = any | Group(lpar + expr + Literal('?') + expr + Literal(':') + expr + rpar) 
expr << atom + ZeroOrMore(expr) 

Ad esempio,

t2 = '(x == 1 ? true : (y == 10 ? 100 : 200))' 
expr.parseString(t2) 
([(['x == 1 ', '?', 'true ', ':', (['y == 10 ', '?', '100 ', ':', '200'], {})], {})], {}) 
+0

Grazie, ho modificato il mio post con la tua risposta. – JB2

+0

Anche se apprezzo molto gli upvotes, l'altra risposta è dello sviluppatore principale di 'pyparsing', quindi forse dovrebbe essere accettata. – xnx

+0

OK :-) Ho trovato la soluzione più facile da capire. Ma leggendo su infixNotation, immagino che la sua soluzione sia il "modo più corretto" di farlo. Grazie xnx! – JB2