2011-01-26 11 views
14

Me gustaría utilizar pyparsing para analizar una expresión de la forma: expr = '(gimme [some {nested [lists]}])', y obtener una lista de pitón de la forma: [[['gimme', ['some', ['nested', ['lists']]]]]]. En este momento mi gramática es el siguiente:¿Cómo puedo usar pyparsing para analizar expresiones anidadas que tienen múltiples tipos de apertura/cierre?

nestedParens = nestedExpr ('(', ')')
nestedBrackets = nestedExpr ('[', ']')
nestedCurlies = nestedExpr ('{', '} ')
cerrados = nestedParens | nestedBrackets | nestedCurlies

Actualmente, enclosed.searchString(expr) devuelve una lista de la forma: [[['gimme', ['some', '{nested', '[lists]}']]]]. Esto no es lo que quiero porque no reconoce los corchetes cuadrados o rizados, pero no sé por qué.

Respuesta

26

he aquí una solución pyparsing que utiliza una gramática propia modificar dinámicamente para que coincida con el carácter de llave de cierre correcta.

from pyparsing import * 

data = '(gimme [some {nested, nested [lists]}])' 

opening = oneOf("({ [") 
nonBracePrintables = ''.join(c for c in printables if c not in '(){}[]') 
closingFor = dict(zip("({[",")}]")) 
closing = Forward() 
# initialize closing with an expression 
closing << NoMatch() 
closingStack = [] 
def pushClosing(t): 
    closingStack.append(closing.expr) 
    closing << Literal(closingFor[t[0]]) 
def popClosing(): 
    closing << closingStack.pop() 
opening.setParseAction(pushClosing) 
closing.setParseAction(popClosing) 

matchedNesting = nestedExpr(opening, closing, Word(alphas) | Word(nonBracePrintables)) 

print matchedNesting.parseString(data).asList() 

impresiones:

[['gimme', ['some', ['nested', ',', 'nested', ['lists']]]]] 

Actualizado: que fijan la solución anterior porque en realidad se había escrito hace más de un año como un experimento. Me tomó un vistazo más de cerca a su puesto original, y me hizo pensar en la definición de tipo recursivo creado por el método operatorPrecedence, y así hice de nuevo esta solución, la utilización de su enfoque original - mucho más simple de seguir! (Podría tener un problema de izquierda recursividad con los datos de entrada de la derecha, sin embargo, no prueba a fondo):

from pyparsing import * 

enclosed = Forward() 
nestedParens = nestedExpr('(', ')', content=enclosed) 
nestedBrackets = nestedExpr('[', ']', content=enclosed) 
nestedCurlies = nestedExpr('{', '}', content=enclosed) 
enclosed << (Word(alphas) | ',' | nestedParens | nestedBrackets | nestedCurlies) 


data = '(gimme [some {nested, nested [lists]}])' 

print enclosed.parseString(data).asList() 

Da:

[['gimme', ['some', ['nested', ',', 'nested', ['lists']]]]] 
+0

Pablo, muchas gracias por la respuesta informativa. ¡Y muchas gracias por crear y abrir mi nueva biblioteca favorita de Python! Pyparsing me está ayudando a reducir drásticamente el tamaño, la complejidad y la capacidad de mantenimiento de un proyecto en el que he estado trabajando. – Derek

+0

Gracias por los cumplidos, bienvenidos a pyparsing! – PaulMcG

-3

Esto debe hacer el truco para usted. Lo he comprobado en su ejemplo:

import re 
import ast 

def parse(s): 
    s = re.sub("[\{\(\[]", '[', s) 
    s = re.sub("[\}\)\]]", ']', s) 
    answer = '' 
    for i,char in enumerate(s): 
     if char == '[': 
      answer += char + "'" 
     elif char == '[': 
      answer += "'" + char + "'" 
     elif char == ']': 
      answer += char 
     else: 
      answer += char 
      if s[i+1] in '[]': 
       answer += "', " 
    ast.literal_eval("s=%s" %answer) 
    return s 

comentario si necesita más

+1

Disculpas por no ser lo suficientemente clara, pero la salida me refiero es una lista de python anidada, que es un resultado común de analizar expresiones anidadas con pyparsing. Su solución solo devuelve una cadena que se parece a una lista de Python impresa. ¡Gracias por tu ayuda! – Derek

+0

@Derek: No devolveré una cadena. Devolveré una lista. La variable llamada respuesta es una cadena, sí; pero esa es la razón por la cual hay una línea que dice que el ejecutivo es "s =% s"% de respuesta. Esto crea una nueva variable llamada s, que es una lista. Es por eso que mi código devuelve s y no responde. Debe comprobar el tipo del valor devuelto, y verá que se trata de una lista, no es una cadena – inspectorG4dget

+3

va a devolver una lista, pero creo que se ha entendido mal lo que el análisis es en este contexto. Cuando analiza una cadena, normalmente tiene acceso a los tokens/grupos coincidentes en el tiempo de análisis, lo que le permite realizar alguna acción sobre ellos. Su programa genera dinámicamente código python y lo ejecuta para transformar una cadena en una lista anidada. No analiza nada, ni utiliza pyparsing como se menciona en la pregunta original. Sin mencionar que ejecutará código de pitón arbitrario, por lo que fallaría en las entradas con comillas, por ejemplo. – Derek

Cuestiones relacionadas