2016-08-07 5 views
4

Использование pyparsing, есть способ извлечь контекст, в котором вы находитесь, во время рекурсивного спуска. Позвольте мне объяснить, что я имею в виду. У меня есть следующий код:сохранение информации о структуре текста - pyparsing

import pyparsing as pp 

openBrace = pp.Suppress(pp.Literal("{")) 
closeBrace = pp.Suppress(pp.Literal("}")) 
ident = pp.Word(pp.alphanums + "_" + ".") 
comment = pp.Literal("//") + pp.restOfLine 
messageName = ident 
messageKw = pp.Suppress(pp.Keyword("msg")) 
text = pp.Word(pp.alphanums + "_" + "." + "-" + "+") 
otherText = ~messageKw + pp.Suppress(text) 
messageExpr = pp.Forward() 
messageExpr << (messageKw + messageName + openBrace + 
       pp.ZeroOrMore(otherText) + pp.ZeroOrMore(messageExpr) + 
       pp.ZeroOrMore(otherText) + closeBrace).ignore(comment) 
testStr = "msg msgName1 { some text msg msgName2 { some text } some text }" 
print messageExpr.parseString(testStr) 

, который производит этот выход: ['msgName1', 'msgName2']

В выходных данных, я хотел бы, чтобы следить за структурой вложенных матчей. Я имею в виду, например, что я хотел бы получить следующий результат с тестовой строкой выше: ['msgName1', 'msgName1.msgName2'] для отслеживания иерархии в тексте. Однако я новичок в pyparsing и еще не нашел пути для извлечения факта, что «msgName2» встроен в структуру «msgName1».

Есть ли способ использовать метод setParseAction() для ParserElement, чтобы сделать это, или, может быть, использовать именование результатов?

Полезный совет будет оценен.

+1

Приложить действие синтаксического анализа для 'messageName' нажать имя на внешний стек , и приложите действие синтаксического анализа, чтобы закрытьBrace, чтобы вытащить эту фамилию из стека. В первом действии синтаксического анализа после нажатия текущего имени в стек вы можете заменить имя в токенах ввода на 'tokens [0] = '.'. Join (stack)' – PaulMcG

ответ

2

Спасибо Пол МакГуайр за его советский совет. Вот дополнения/изменения, которые я сделал, которые решали задачу:

msgNameStack = [] 

def pushMsgName(str, loc, tokens): 
    msgNameStack.append(tokens[0]) 
    tokens[0] = '.'.join(msgNameStack) 

def popMsgName(str, loc, tokens): 
    msgNameStack.pop() 

closeBrace = pp.Suppress(pp.Literal("}")).setParseAction(popMsgName) 
messageName = ident.setParseAction(pushMsgName) 

А вот полный код:

import pyparsing as pp 

msgNameStack = [] 


def pushMsgName(str, loc, tokens): 
    msgNameStack.append(tokens[0]) 
    tokens[0] = '.'.join(msgNameStack) 


def popMsgName(str, loc, tokens): 
    msgNameStack.pop() 

openBrace = pp.Suppress(pp.Literal("{")) 
closeBrace = pp.Suppress(pp.Literal("}")).setParseAction(popMsgName) 
ident = pp.Word(pp.alphanums + "_" + ".") 
comment = pp.Literal("//") + pp.restOfLine 
messageName = ident.setParseAction(pushMsgName) 
messageKw = pp.Suppress(pp.Keyword("msg")) 
text = pp.Word(pp.alphanums + "_" + "." + "-" + "+") 
otherText = ~messageKw + pp.Suppress(text) 
messageExpr = pp.Forward() 
messageExpr << (messageKw + messageName + openBrace + 
       pp.ZeroOrMore(otherText) + pp.ZeroOrMore(messageExpr) + 
       pp.ZeroOrMore(otherText) + closeBrace).ignore(comment) 

testStr = "msg msgName1 { some text msg msgName2 { some text } some text }" 
print messageExpr.parseString(testStr)