3

我是 pyparsing 的新手,一直在阅读示例,在这里查看并尝试了一些东西。我创建了一个语法并提供了一个缓冲区。然而,我在过去的 lex/yacc 方面确实有丰富的背景。

我有一两个一般性问题。

我目前正在看

ParseException:预期的行尾(在 char 7024 处),(第 213 行,col:2)

然后它终止

由于我的缓冲区的性质,换行符有意义,我做了:

ParserElement.setDefaultWhitespaceChars('') # <-- zero len string

这个错误是否意味着在我的作品中的某个地方,我有一条正在寻找的规则,LineEnd()而这条规则恰好是“最后一个”?

它正在消亡的位置是“文件结尾”。我尝试使用parseFile但我的文件包含 chars > ord(127) 所以我将它加载到内存中,过滤所有 > ord(127) 字符,然后调用parseString.

我尝试打开verbose_stacktrace=True我认为问题所在的一些语法元素。

有没有更好的方法来追踪ParserElement它试图识别何时发生此类错误?或者我可以获得“堆栈或最近识别的生产跟踪”吗?

我没有意识到我可以在这里编辑......我的崩溃是这样的:

[centos@new-host /tmp/sample]$  ./zooparser.py 
!(zooparser.py) TEST test1: valid message type START
Ready to roll
Parsing This message: ( ignore leading>>> and trailing <<< ) >>>

ZOO/STATUS/FOOD ALLOCATION//
TOPIC/BIRD FEED IS RUNNING LOW//
FREE/WE HAVE DISCOVERED MOTHS INFESTED THE BIRDSEED AND IT IS NO
LONGER USABLE.//

<<<
Match {Group:({Group:({Group:({[LineEnd]... "ZOO" Group:({[LineEnd]... "/" [Group:({{{W:(abcd...) | LineEnd | "://" | " " | W:(!@#$...) | ":"}}... ["/"]...})]... {W:(abcd...) | LineEnd | "://" | "    " | W:(!@#$...)}}) "//"}) Group:({LineEnd "TOPIC" {Group:({[LineEnd]... Group:({"/" {W:(abcd...) | Group:({W:(abcd...) [{W:(abcd...)}...]... W:(abcd...)}) | Group:({{{"ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ'"}... | Group:({{"0123456789"}... ":"})} {W:(abcd...) | Group:({W:(abcd...) [{W:(abcd...)}...]... W:(abcd...)})}}) | "-"}})})}... [LineEnd]... "//"})}) [Group:({LineEnd "FREE" Group:({[LineEnd]... "/" [Group:({{{W:(abcd...) | LineEnd | "://" | "  " | W:(!@#$...) | ":"}}... ["/"]...})]... {W:(abcd...) | LineEnd | "://" | "    " | W:(!@#$...)}}) "//"})]...}) [LineEnd]... StringEnd} at loc 0(1,1)
Match Group:({Group:({[LineEnd]... "ZOO" Group:({[LineEnd]... "/" [Group:({{{W:(abcd...) | LineEnd | "://" | "  " | W:(!@#$...) | ":"}}... ["/"]...})]... {W:(abcd...) | LineEnd | "://" | "    " | W:(!@#$...)}}) "//"}) Group:({LineEnd "TOPIC" {Group:({[LineEnd]... Group:({"/" {W:(abcd...) | Group:({W:(abcd...) [{W:(abcd...)}...]... W:(abcd...)}) | Group:({{{"ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ'"}... | Group:({{"0123456789"}... ":"})} {W:(abcd...) | Group:({W:(abcd...) [{W:(abcd...)}...]... W:(abcd...)})}}) | "-"}})})}... [LineEnd]... "//"})}) at loc 0(1,1)
Match Group:({[LineEnd]... "ZOO" Group:({[LineEnd]... "/" [Group:({{{W:(abcd...) | LineEnd | "://" | "  " | W:(!@#$...) | ":"}}... ["/"]...})]... {W:(abcd...) | LineEnd | "://" | "    " | W:(!@#$...)}}) "//"}) at loc 0(1,1)
Exception raised:None
Exception raised:None
Exception raised:None
Traceback (most recent call last):
  File "./zooparser.py", line 319, in <module>
    test1(pgm)
  File "./zooparser.py", line 309, in test1
    test(pgm, zooMsg, 'test1: valid message type' )
  File "./zooparser.py", line 274, in test
    tokens = zg.getTokensFromBuffer(fileName)
  File "./zooparser.py", line 219, in getTokensFromBuffer
    tokens = self.text.parseString(filteredBuffer,parseAll=True)
  File "/usr/local/lib/python2.7/site-packages/pyparsing-1.5.7-py2.7.egg/pyparsing.py", line 1006, in parseString
    raise exc
pyparsing.ParseException: Expected end of line (at char 148), (line:8, col:2)
[centos@new-host /tmp/sample]$  

来源:见http://prj1.y23.org/zoo.zip

4

1 回答 1

2

pyparsing 对解析的看法与 lex/yacc 不同。你必须让班级做一些工作。这是您的代码中的一个示例:

    self.columnHeader = OneOrMore(self.aucc) \
                        | OneOrMore(nums) \
                        | OneOrMore(self.blankCharacter) \
                        | OneOrMore(self.specialCharacter)

您等同OneOrMore于正则表达式的“+”字符。在 pyparsing 中,ParseElements 也是如此,但在字符级别,pyparsing 使用Word类:

    self.columnHeader = Word(self.aucc + nums + self.blankCharacter + self.specialCharacter)

OneOrMore适用于 ParseElements,而不是字符。看着:

    OneOrMore(nums)

nums是字符串“0123456789”,因此OneOrMore(nums)将匹配“0123456789”、“01234567890123456789”等,但不匹配“123”。这就是Word目的。OneOrMore将接受字符串参数,但会将其隐式转换为Literal.

这是使用 pyparsing 和 lex/yacc 之间的根本区别,我认为这是代码中大部分复杂性的根源。

其他一些建议:

您的代码中有一些过早的优化 - 您编写:

aucc = ''.join(set([alphas.upper(),"'"]))

假设这将用于定义单词,只需执行以下操作:

aucc = alphas.upper() + "'"

在 aucc 中有重复字符没有害处,Word它将在内部将其转换为一个集合。

为要解析的内容编写 BNF。它不必像 lex/yacc 那样过于严格。从您的样本中,它看起来像:

# sample
ZOO/STATUS/FOOD ALLOCATION//
TOPIC/BIRD FEED IS RUNNING LOW//
FREE/WE HAVE DISCOVERED MOTHS INFESTED THE BIRDSEED AND IT IS NO
LONGER USABLE.//

parser :: header topicEntry+
header :: "ZOO" sep namedValue
namedValue :: uppercaseWord sep valueBody
valueBody :: (everything up to //)
topicEntry :: topicHeader topicBody
topicHeader :: "TOPIC" sep valuebody
topicBody :: freeText
freeText :: "FREE" sep valuebody
sep :: "/"

转换为 pyparsing,这看起来像:

SEP = Literal("/")
BODY_TERMINATOR = Literal("//")
FREE_,TOPIC_,ZOO_ = map(Keyword,"FREE TOPIC ZOO".split())
uppercaseWord = Word(alphas.upper())
valueBody = SkipTo(BODY_TERMINATOR) # adjust later, but okay for now...

freeText = FREE_ + SEP + valueBody

topicBody = freeText
topicHeader = TOPIC_ + SEP + valueBody
topicEntry = topicHeader + topicBody

namedValue = uppercaseWord + SEP + valueBody
zooHeader = ZOO_ + SEP + namedValue

parser = zooHeader + OneOrMore(topicEntry)

valueBody当您添加对嵌入值中的“://”的支持时,必须更加详细,但将其保存到第 2 轮。)

不要让事情变得超级复杂,直到你至少让一些简单的东西工作。

于 2013-07-13T09:39:03.330 回答