Как я могу использовать pyparsing для анализа вложенных выражений, которые имеют несколько типов открывающих / приближающих? - PullRequest
15 голосов
/ 26 января 2011

Я бы хотел использовать pyparsing для анализа выражения в форме: expr = '(gimme [some {nested [lists]}])' и получить список питонов в форме: [[['gimme', ['some', ['nested', ['lists']]]]]].Прямо сейчас моя грамматика выглядит следующим образом:

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

В настоящее время enclosed.searchString(expr) возвращает список в форме: [[['gimme', ['some', '{nested', '[lists]}']]]].Это не то, чего я хочу, потому что он не распознает квадратные или фигурные скобки, но я не знаю почему.

Ответы [ 2 ]

27 голосов
/ 26 января 2011

Вот решение для разбора, которое использует самоизменяющуюся грамматику для динамического соответствия правильному символу закрывающей скобки.

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()

печатает:

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

Обновлено: Я разместил вышеупомянутое решение, потому что фактически написал его более года назад в качестве эксперимента.Я просто более внимательно посмотрел на ваш исходный пост, и он заставил меня задуматься о рекурсивном определении типа, созданном методом operatorPrecedence, и поэтому я переделал это решение, используя ваш оригинальный подход - гораздо проще следовать!(может возникнуть проблема левой рекурсии с правыми входными данными, хотя и не полностью проверена):

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()

Дает:

[['gimme', ['some', ['nested', ',', 'nested', ['lists']]]]]
0 голосов
/ 26 января 2011

Это должно помочь вам.Я проверил это на вашем примере:

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

Комментарий, если вам нужно больше

...