尝试使用 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)
我在尝试使用 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)