Pyparsing - 规则歧义

时间:2015-04-15 02:57:42

标签: python parsing markup pyparsing creole

我正在编写一个Pyparsing语法来将Creole markup转换为HTML。我被困了,因为试图解析这两个结构有一些冲突:

图片链接:{{image.jpg | title}}
忽略格式:{{{text}}}

我正在解析图像链接的方式如下(请注意,此转换完全正常):

def parse_image(s, l, t):
    try:
        link, title = t[0].split("|")
    except ValueError:
        raise ParseFatalException(s,l,"invalid image link reference: " + t[0])
    return '<img src="{0}" alt="{1}" />'.format(link, title)

image = QuotedString("{{", endQuoteChar="}}")
image.setParseAction(parse_image)

接下来,我编写了一条规则,以便在遇到{{{text}}}时,只需返回开始和结束括号之间的内容而不进行格式化:

n = QuotedString("{{{", endQuoteChar="}}}")
n.setParseAction(lambda x: x[0])

但是,当我尝试运行以下测试用例时:

text = italic | bold | hr | newline | image | n
print text.transformString("{{{ //ignore formatting// }}}")

我得到以下堆栈跟踪:

Traceback (most recent call last):
File "C:\Users\User\py\kreyol\parser.py", line 36, in <module>
print text.transformString("{{{ //ignore formatting// }}}")
File "C:\Python27\lib\site-packages\pyparsing.py", line 1210, in transformString
raise exc
pyparsing.ParseFatalException: invalid image link reference: { //ignore formatting//  (at char 0), (line:1, col:1)

根据我的理解,解析器遇到{{first并尝试将文本解析为图像而不是文本而不进行格式化。我怎样才能解决这种歧义?

1 个答案:

答案 0 :(得分:3)

问题在于这个表达式:

text = italic | bold | hr | newline | image | n

Pyparsing严格按照从左到右的方式进行,没有前瞻性。使用&#39; |&#39;运算符,你构造一个pyparsing MatchFirst表达式,它将匹配所有备选方案的第一个匹配,即使后来的匹配更好。

您可以将评估更改为使用&#34;最长匹配&#34;通过使用&#39; ^&#39;而不是运营商:

text = italic ^ bold ^ hr ^ newline ^ image ^ n

即使没有更好的匹配可能性,也会对每个表达式进行性能测试。

更简单的解决方案是重新排序备选列表中的表达式:在n之前测试image

text = italic | bold | hr | newline | n | image

现在,在评估替代方案时,它会在{{{的前导n之前查找{{的前导image

当人们定义数字术语时,这通常会突然出现,并且意外地定义了类似的内容:

integer = Word(nums)
realnumber = Combine(Word(nums) + '.' + Word(nums))
number = integer | realnumber

在这种情况下,number永远不会匹配realnumber,因为前导整数部分将被解析为整数。在您的情况下,修复方法是使用&#39; ^&#39;运营商,或只是重新订购:

number = realnumber | integer