我正在尝试使用pyparsing解析可以通过反斜杠-换行符组合("\\n
")跨多行的单词。这是我的做法:
from pyparsing import *
continued_ending = Literal('\\') + lineEnd
word = Word(alphas)
split_word = word + Suppress(continued_ending)
multi_line_word = Forward()
multi_line_word << (word | (split_word + multi_line_word))
print multi_line_word.parseString(
'''super\\
cali\\
fragi\\
listic''')
我得到的输出是
['super']
,而期望的输出是['super','cali','fragi','listic']
。更好的方法是将它们全部作为一个单词连接起来(我认为可以使用multi_line_word.parseAction(lambda t: ''.join(t))
实现)。我尝试在pyparsing helper中查看此代码,但出现错误
maximum recursion depth exceeded
。
编辑2009-11-15:后来我意识到pyparsing对于空格有些慷慨,这导致了一些错误的假设,我认为我解析的内容更加宽松。也就是说,我们希望在单词的任何部分、转义字符和EOL字符之间都没有空格。我意识到上面的小例子字符串不足以作为测试用例,因此我编写了以下单元测试。通过这些测试的代码应该能够匹配我在直觉上认为的转义分割词——而且 只有 转义分割词。它们不会匹配不是转义分割的基本单词。我们可以——而且我相信应该——为此使用不同的语法结构。这样将两者分开可以使它们更整洁。
import unittest
import pyparsing
# Assumes you named your module 'multiline.py'
import multiline
class MultiLineTests(unittest.TestCase):
def test_continued_ending(self):
case = '\\\n'
expected = ['\\', '\n']
result = multiline.continued_ending.parseString(case).asList()
self.assertEqual(result, expected)
def test_continued_ending_space_between_parse_error(self):
case = '\\ \n'
self.assertRaises(
pyparsing.ParseException,
multiline.continued_ending.parseString,
case
)
def test_split_word(self):
cases = ('shiny\\', 'shiny\\\n', ' shiny\\')
expected = ['shiny']
for case in cases:
result = multiline.split_word.parseString(case).asList()
self.assertEqual(result, expected)
def test_split_word_no_escape_parse_error(self):
case = 'shiny'
self.assertRaises(
pyparsing.ParseException,
multiline.split_word.parseString,
case
)
def test_split_word_space_parse_error(self):
cases = ('shiny \\', 'shiny\r\\', 'shiny\t\\', 'shiny\\ ')
for case in cases:
self.assertRaises(
pyparsing.ParseException,
multiline.split_word.parseString,
case
)
def test_multi_line_word(self):
cases = (
'shiny\\',
'shi\\\nny',
'sh\\\ni\\\nny\\\n',
' shi\\\nny\\',
'shi\\\nny '
'shi\\\nny captain'
)
expected = ['shiny']
for case in cases:
result = multiline.multi_line_word.parseString(case).asList()
self.assertEqual(result, expected)
def test_multi_line_word_spaces_parse_error(self):
cases = (
'shi \\\nny',
'shi\\ \nny',
'sh\\\n iny',
'shi\\\n\tny',
)
for case in cases:
self.assertRaises(
pyparsing.ParseException,
multiline.multi_line_word.parseString,
case
)
if __name__ == '__main__':
unittest.main()
Combine
也强制不插入空格。 - PaulMcGmulti_line_word = Combine(Combine(OneOrMore(split_word)) + Optional(word))
但是在处理'sh\\\n iny'
这种情况时,它没有引发异常,而是返回了['sh']
。我有什么遗漏吗? - gotgenesmulti_line_word.parseString('sh\\\n iny')
抛出ParseException
,而不是将'sh'
识别为其标记。在这种情况下,'sh'
和'iny'
是两个单词,而不是一个破碎单词的一部分,因为'iny'
部分与EOL不连续。因此,multi_line_word
不应该识别它。它应该举起双手说,“这不是一个有效的破碎单词!” - gotgenes