Acceda a elementos analizados utilizando Pyparsing
Tengo un montón de oraciones que necesito analizar y convertir al código de búsqueda de expresiones regulares correspondiente. Ejemplos de mis oraciones -
LINE_CONTAINS phrase one BEFORE {phrase2 AND phrase3} AND LINE_STARTSWITH Therefore we
-Esto significa en la línea,phrase one
viene a alguna parte antesphrase2
yphrase3
. Además, la línea debe comenzar conTherefore we
LINE_CONTAINS abc {upto 4 words} xyz {upto 3 words} pqr
-Esto significa que necesito permitir hasta 4 palabras entre las primeras 2 frases y hasta 3 palabras entre las últimas 2 frases
Usando la ayuda de Paul Mcguire (aquí), se escribió la siguiente gramática:
from pyparsing import (CaselessKeyword, Word, alphanums, nums, MatchFirst, quotedString,
infixNotation, Combine, opAssoc, Suppress, pyparsing_common, Group, OneOrMore, ZeroOrMore)
LINE_CONTAINS, LINE_STARTSWITH = map(CaselessKeyword,
"""LINE_CONTAINS LINE_STARTSWITH """.split())
NOT, AND, OR = map(CaselessKeyword, "NOT AND OR".split())
BEFORE, AFTER, JOIN = map(CaselessKeyword, "BEFORE AFTER JOIN".split())
lpar=Suppress('{')
rpar=Suppress('}')
keyword = MatchFirst([LINE_CONTAINS, LINE_STARTSWITH, LINE_ENDSWITH, NOT, AND, OR,
BEFORE, AFTER, JOIN]) # declaring all keywords and assigning order for all further use
phrase_word = ~keyword + (Word(alphanums + '_'))
upto_N_words = Group(lpar + 'upto' + pyparsing_common.integer('numberofwords') + 'words' + rpar)
phrase_term = Group(OneOrMore(phrase_word) + ZeroOrMore((upto_N_words) + OneOrMore(phrase_word))
phrase_expr = infixNotation(phrase_term,
[
((BEFORE | AFTER | JOIN), 2, opAssoc.LEFT,), # (opExpr, numTerms, rightLeftAssoc, parseAction)
(NOT, 1, opAssoc.RIGHT,),
(AND, 2, opAssoc.LEFT,),
(OR, 2, opAssoc.LEFT),
],
lpar=Suppress('{'), rpar=Suppress('}')
) # structure of a single phrase with its operators
line_term = Group((LINE_CONTAINS | LINE_STARTSWITH | LINE_ENDSWITH)("line_directive") +
Group(phrase_expr)("phrase")) # basically giving structure to a single sub-rule having line-term and phrase
line_contents_expr = infixNotation(line_term,
[(NOT, 1, opAssoc.RIGHT,),
(AND, 2, opAssoc.LEFT,),
(OR, 2, opAssoc.LEFT),
]
) # grammar for the entire rule/sentence
sample1 = """
LINE_CONTAINS phrase one BEFORE {phrase2 AND phrase3} AND LINE_STARTSWITH Therefore we
"""
sample2 = """
LINE_CONTAINS abcd {upto 4 words} xyzw {upto 3 words} pqrs BEFORE something else
"""
Mi pregunta ahora es: ¿cómo accedo a los elementos analizados para convertir las oraciones a mi código regex? Para esto, probé lo siguiente:
parsed = line_contents_expr.parseString(sample1)/(sample2)
print (parsed[0].asDict())
print (parsed)
pprint.pprint(parsed)
El resultado del código anterior parasample1
estaba -
{}
[[['LINE_CONTAINS', [[['' oración ',' uno '],' ANTES ', [[' oración2 '],' AND ', [' oración3 ']]]]],' AND ', [' LINE_STARTSWITH ', [[' 'Por lo tanto', 'nosotros']]]]]
([([(['LINE_CONTAINS', ([([([oración ',' uno '], {}),' ANTES ', ([([' oración2 '], {}),' Y ', (['oración3'], {})], {})], {})], {})], {'frase': [(([([([' oración ',' uno '], {}),' ANTES ', ([([' oración2 '], {}),' AND ', ([' oración3 '] , {})], {})], {})], {}), 1)], 'line_directive': [(' LINE_CONTAINS ', 0)]}),' AND ', ([' LINE_STARTSWITH ', ([(' 'Por lo tanto,' nosotros '], {})], {})], {'frase': [(([([' 'Por lo tanto,' nosotros '], {})], {}), 1)],'line_directive': [(' LINE_STARTSWITH ', 0)]})], {})], {})
El resultado del código anterior parasample2
estaba -
{'frase': [[['a B C D', {'número de palabras': 4},' xyzw ', {'número de palabras': 3},' pqrs '],' ANTES ', [' algo ',' más ']]],'line_directive':' LINE_CONTAINS '}
[['LINE_CONTAINS', [[['' abcd ', [' upto ', 4,' palabras '],' xyzw ', [' upto ', 3,' palabras '],' pqrs '],' ANTES ', ['algo más']]]]]
([(['' LINE_CONTAINS ', ([([([' abcd ', ([' upto ', 4,' palabras '], {'número de palabras': [(4, 1)]}),' xyzw ', ([' 'hasta', 3, 'palabras'], {'número de palabras': [(3, 1)]}),' pqrs '], {}),' ANTES ', ([' algo ',' más '], {})], {})], {})] , {'frase': [(([([(['' abcd ', ([' 'hasta', 4, 'palabras'], {'número de palabras': [(4, 1)]}),' xyzw ', ([' 'hasta', 3, 'palabras'], {'número de palabras': [(3, 1)]}), 'pqrs'], { }), 'ANTES', (['algo', 'más'], {})], {})], {}), 1)], 'line_directive': [(' LINE_CONTAINS ', 0)]})], {})
Mis preguntas basadas en el resultado anterior son:
¿Por qué el pprint (impresión bonita) tiene un análisis más detallado que la impresión normal?¿Por qué elasDict()
método no da salida parasample1
pero lo hace porsample2
?Cada vez que intento acceder a los elementos analizados usandoprint (parsed.numberofwords)
oparsed.line_directive
oparsed.line_term
No me da nada. ¿Cómo puedo acceder a estos elementos para usarlos para construir mis códigos regex?