pyparsing ParseException:预期的行尾 - 一般问题

时间:2013-07-12 16:19:30

标签: python parsing pyparsing

我是pyparsing的新手,一直在阅读这些例子,看这里并尝试一些事情。 我创建了一个语法并提供了一个缓冲区。然而,我在过去的lex / yacc中有着沉重的背景。

我有一两般的问题。

我现在正在看

  

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

然后终止

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

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

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

它正在死亡的位置是“文件结束”。我尝试使用parseFile但我的文件包含字符&gt; ord(127)所以我把它加载到内存中,过滤所有&gt; ord(127)chars,然后调用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

1 个答案:

答案 0 :(得分: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轮。)

在你至少完成一些简单的工作之前,不要让事情变得非常复杂。