怀疑pyparsing最长匹配错误

时间:2016-07-08 02:49:17

标签: python parsing pyparsing

我正在为DOT语言开发一个解析器,并且遇到了“子图”语句的问题。

我的SUBGRAPH解析表达式正常工作没有问题(参见下面的片段)但是当我在STMT中添加它作为替代时它无法匹配。

简单测试:

test = '''subgraph cluster01 { n003 ; n004 ;  }'''
FRAG_1 = SUBGRAPH + StringEnd()
FRAG_2 = STMT + StringEnd()

res1 = FRAG_1.parseString(test)  # OK
res2 = FRAG_2.parseString(test)  # ParseException - 

错误:

subgraph cluster01 { n003 ; n004 ;  }
         ^
ERROR: Expected end of text (at char 9), (line:1, col:10)

怀疑问题涉及我的STMT表达式 - 它贪婪地将关键字“subgraph”与NODE_STMT匹配而不是匹配为SUBGRAPH但是我的期望是通过使用“Or”表达式( “^”)最长匹配算法将选择SUBGRAPH而不是NODE_STMT。或者它可能是别的东西。

我的部分语法如下:

语法片段:

LCURL = Literal("{").suppress()
RCURL = Literal("}").suppress()
STMTSEP = Literal(";").suppress()
ID = Word(alphas, alphanums + "_")
SUBGRAPH_KW = Keyword("subgraph", caseless=True)
SUBGRAPH = Forward("SUBGRAPH")

NODE_ID = ID("NODE_ID")
NODE_STMT = NODE_ID("NODE")

STMT = NODE_STMT("NODE") ^ SUBGRAPH("SUBGRAPH")
STMT_LIST = ZeroOrMore(STMT("STMT") + Optional(STMTSEP))

SUBGRAPH << Group(SUBGRAPH_KW + ID("SUBGRAPHNAME")) + Group(LCURL +    STMT_LIST + RCURL)

2 个答案:

答案 0 :(得分:1)

这是因为您要在此行中创建SUBGRAPH对象的副本

STMT = NODE_STMT("NODE") ^ SUBGRAPH("SUBGRAPH")

调用setResultsName(),其中调用语法是creates a copy of the ParserElement object的快捷方式。

这是一个问题,因为SUBGRAPH是一个Forward对象,而且在代码中它尚未完全定义。

你真的不应该随时随地为所有事情设置名称!在实际需要的时间和地点执行此操作,并记住它会创建ParserElement个对象的副本。

答案 1 :(得分:0)

一般情况下,我建议暂停分配结果名称,直到将表达式汇编为更高级别的表达式,如下所示:

intnum = Word(nums).setParseAction(lambda t: int(t[0]))
realnum = Combine(Word(nums) + '.' + Word(nums)).setParseAction(lambda t: float(t[0]))
hostname = Word(alphas, alphanums+'-')
timestamp = Regex(r'\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d')
statslogentry = (timestamp('timestamp') + hostname('hostname') + 
                 'CPU:' + realnum('cpu') + 
                 'DISK_IO:' + intnum('disk_io') + 
                 'NETWORK_IO:' + intnum('network_io'))

但是,使用Forward时,这可能会对您不利,就像这里的情况一样。 OP代码中的一个特定错误是

SUBGRAPH = Forward("SUBGRAPH")

我认为OP正在尝试使用结果名称快捷方式,但实际上是在创建一个内容为Forward的{​​{1}}。将此更改为

Literal("SUBGRAPH")

并从SUBGRAPH = Forward()("SUBGRAPH") 表达式中删除结果名称将解决原始问题。但我仍然认为这有点落入&#34;陷阱&#34;类别。