没有从特定语法的pyparsing得到预期的结果

时间:2014-07-30 18:45:59

标签: python pyparsing

我有一个二进制线协议配置文件,我试图解析。这用于允许低带宽链路两侧的计算机同意哪些位代表哪些数据允许用户在现场配置它们。

配置文件字符串如下所示:

abc:16 =>标识符abc有16位

abc:16 def:12 =>标识符abc有16位,标识符def有12

abc:16:p =>标识符abc具有16位和单个奇偶校验位

abc:16:ecc =>标识符abc有16位,ecc

有两位

我已经达到了一个语法,我认为我应该正确地解析这个问题,但我遇到了一个奇怪的问题:我只能有一个没有奇偶校验的标识符或ecc作为最后一个语句在一条线上。语法应该支持在行上的任何地方都有或不带奇偶校验的标识符,但无论出于何种原因都不会发生。

所以:
ABC:16个
它本身就没问题,因为它之后什么也没有。

abc:16:p def:12
没问题,因为abc:16:p在结尾有一个奇偶校验

abc:16 def:12
是不行的,因为abc:16没有奇偶校验而且它不在最后,但这应该没问题

abc:16 def:12:p
也不行,因为非奇偶校验陈述不在最后,但这也应该完全没问题

以下是该计划:

from pyparsing import *
import re

abbr = Word(alphas, min=3, max=4)
#abbr = abbr.setDebug()

separator = Suppress(Literal(":"))
bits = Word(nums, min=1, max=2)
parity = Or([CaselessLiteral("P"), CaselessLiteral("ECC")])

bits_part = separator + bits
#bits_part = bits_part.setDebug()

parity_part = separator + parity
#parity_part = parity_part.setDebug()

statement = abbr + bits_part + Optional(parity_part)
#statement = statement.setDebug()

statement_list = StringStart() + statement + ZeroOrMore(Suppress(White()) + statement) + Optional(Suppress(White())) + StringEnd()

tests = ( 
    "abc:16",
    "abc:15:p", 
    "abc:15:p def:14:ecc",
    "abc:17:p def:q ghi:21:", #this one should fail since "q" isn't parity and you shouldn't have a trailing colon with no parity after it
    "abc:16:p def:12", #this passes so it's OK to have a trailing statement without parity
    "abc:15 def:12:p", #this fails but shouldn't
    "abc:16:p def:12 pqr:11", #this is also failing because anything but the last statement missing parity causes failure, but I don't think that's the right behavior
)

for t in tests:
    try:
        print t
        print statement_list.parseString(t)
    except Exception as e:
        print e

当我在未启用调试的情况下运行它时,我看到以下结果。根据我的理解(以及上面的评论),只有第三个例子应该失败,因为它有" q" " p"对于平价应该是。其他一切都应该通过,但由于我不理解的原因而引发异常。

abc:16
['abc', '16']
abc:15:p
['abc', '15', 'P']
abc:15:p def:14:ecc
['abc', '15', 'P', 'def', '14', 'ECC']
abc:17:p def:q ghi:21:
Expected end of text (at char 9), (line:1, col:10)
abc:16:p def:12
['abc', '16', 'P', 'def', '12']
abc:15 def:12:p
Expected end of text (at char 7), (line:1, col:8)
abc:16:p def:12 pqr:11
Expected end of text (at char 16), (line:1, col:17)

当我打开调试时(它在上面的示例代码中都被注释掉了)我只看了" abc:16 def:12"这是输出:

abc:15 def:12:p
Match {W:(abcd...) {Suppress:(":") W:(0123...)} [{Suppress:(":") {'P' ^ 'ECC'}}]} at loc 0(1,1)
Match W:(abcd...) at loc 0(1,1)
Matched W:(abcd...) -> ['abc']
Match {Suppress:(":") W:(0123...)} at loc 3(1,4)
Matched {Suppress:(":") W:(0123...)} -> ['15']
Match {Suppress:(":") {'P' ^ 'ECC'}} at loc 7(1,8)
Exception raised:Expected ":" (at char 7), (line:1, col:8)
Matched {W:(abcd...) {Suppress:(":") W:(0123...)} [{Suppress:(":") {'P' ^ 'ECC'}}]} -> ['abc', '15']
Expected end of text (at char 7), (line:1, col:8)

在我看来,它确认它正在尝试匹配parity_part,这显然不存在。但是我已经设置了这个,所以parity_part是Optional()所以我无法弄清楚它为什么坚持找到它。

此外还有一个空白字符(在abc:16和def:12之间),我觉得它应该触发它继续前进,就像我在语法的statement_list部分中指定的那样。为此,我还提到了一个" leaveWhitespace()"最后打电话给练习者:

print statement_list.parseString(t).leaveWhitespace()

但这并没有改变任何事情(因为它没有开始解析我期望的方式)所以我不相信问题在于它错过了空白。我当然不能完全打折它。

我在这里感到非常困惑,因为我已经从我能想到的每个角度解决了这个问题,而且我仍然没有得到我期望的结果。我指的语法错了吗? pyparsing做错了吗?我对自己在某个地方犯了错误感到非常自信,但我真的无法看到它。

编辑:

所以保罗已经指出我到处都有一堆愚蠢的空白东西,当他把所有这些都弄糟时,简化的东西运转良好。空白的东西是故意的,因为我试图阻止人们做类似的事情:

" abc:10:ecc"

因为它看起来不好,不是因为它没有包含正确的信息。

我不确定这对我来说是否值得阻止人们把空间放在我认为他们不应该这样做的地方所以保罗的回答可能足以让我继续我的继续寿命。

但我仍然很好奇为什么我制作的版本没有工作,他所做的修改也是如此。它们在功能上与我相当。

1 个答案:

答案 0 :(得分:2)

知道pyparsing会自己跳过空格,是吗?

我通过将statement_list定义为plain:

来实现此目的
statement_list = OneOrMore(statement)

要保持多个语句一起运行,您应该使用Group:

statement_list = OneOrMore(Group(statement))

而不是添加自己的StringEnd来强制解析器尝试处理完整的字符串,而是使用parseAll=True

print statement_list.parseString(t, parseAll=True)