尝试使用 pyparsing 解析重复字符时出错

Error trying to parse repeat characters with pyparsing

我在尝试使用 pyparsing 解析某些文本时出现意外行为。我正在逐行解析一些半结构化文本,可能的行之一是记录分隔符,它由整行“=”字符组成,如下所示:

'========================================== ======'

也有可能此时出现空行,只好两种都试了。如果我尝试使用以下定义(假设 import pyparsing as pp)解析仅由白色 space 组成的行:pp.Word('=', min=10),我得到一个 IndexError: string index out of range 错误而不是预期的 pyparsing不匹配的例外。定义 pp.OneOrMore(pp.Word('=')) 具有预期的行为,因此我当然会在我的代码中使用它。我的理解是这些定义在这种情况下应该是等价的,并且 pyparsing 应该 return 一个 ParseException 而不是 IndexError。我错过了什么吗?

import unittest
import pyparsing as pp


class Test(unittest.TestCase):


    def testSepDetail(self):
        verbose = True
        pattern1 = pp.Word('=', min=10) # Throws IndexError: string index out of range
        pattern2 = pp.OneOrMore(pp.Word('=')) # Works as expected
        testPattern = pattern1
        testList = [
('=======================','======================='),
('     ',None)]
        for test in testList:
            text, expected = test
            result = self.harness2(testPattern, text, expected, verbose)

    def harness2(self,pattern, text, expected, verbose):
        '''
        '''

        if verbose:
            print('\n---Test for: {0}'.format(text))
        try:
            result = pattern.parseString(text)
            if verbose:
                print('Parse successful.\n', result.dump())
            if expected:
                self.assertEqual(expected, result[0], "\n\tParse Successful, but data not as expected.\n\tExpected {0}\n\t but got {1}".format(expected, result[0]))
            return result          
        except pp.ParseException as x:
            failmsg = "\n---Failed to parse string: {0}\n{1}".format(text,str(x))
            print(failmsg)
            self.fail(failmsg)


if __name__ == "__main__":
    #import sys;sys.argv = ['', 'Test.testName']
    unittest.main()

这不是您的错误,它是 pyparsing 中的错误,是 re-optimizing 代码在忘记之前以冲突方式优化后的结果。这个问题实际上影响了几个 pyparsing classes,而不仅仅是 Word(主要是那些来自 pyparsing 的 Token class 的 subclass)。

在实践中这不是什么大问题,因为 Token-type 表达式很少单独使用,容器表达式如 OneOrMore 等都会捕获 IndexError 并重新引发 ParseException。

例如,这些也可以解决 Word 中的 IndexError 问题:

pattern2 = pp.empty + pp.Word('=')
pattern2 = 1*pp.Word('=')

我一定会为下一个版本清理它,但在你的应用程序中,我认为如果你将你的处理程序更改为:

except (pp.ParseException, IndexError) as x:

那么当你升级到固定版本时,你只需要改变一个 except 语句,而不是你用 OneOrMore hack 的语法中的所有地方。

注意:如果您将 self.fail 调用更改为:

,您还可以让您的测试平台容忍异常情况
        if expected is not None:
            self.fail(failmsg)