使用 pyparsing 在多行上捕获块
Capturing block over multiple lines using pyparsing
正在尝试分析多行文档中的多项选择。想要捕获每个关键字之间的所有行。这是一个例子:
Keyword 1: CAPTURE THIS TEXT
Keyword 2: CAPTURE THIS TEXT
Keyword 3:
CAPTURE THIS TEXT
CAPTURE THIS TEXT
CAPTURE THIS TEXT
Keyword 4
我可能也有
Keyword 1: CAPTURE THIS TEXT
CAPTURE THIS TEXT
Keyword 2: CAPTURE THIS TEXT
Keyword 3:
CAPTURE THIS TEXT
CAPTURE THIS TEXT
CAPTURE THIS TEXT
CAPTURE THIS TEXT
Keyword 4
我的代码看起来像
from pyparsing import *
EOL = LineEnd().suppress()
line = OneOrMore(Group(SkipTo(LineEnd()) + EOL))
KEYWORD_CAPTURE_AREA = Keyword("Keyword 1:").suppress() + line + Keyword("Keyword 2:").suppress() + line \
+ Keyword("Keyword 3:").suppress() + line + Keyword("Keyword 4").suppress()
当前方法 returns 如果我的结果跨越多行,则没有结果。假设应该有一个直接的解决方案 - 只是还没有找到它。
一定要pyparsing
吗?
如果没有,您可以使用拆分,例如
f = open('sample.txt')
values = []
for text in f.read().split('Keyword '):
values.append(text[2:])
print(values)
>> ['', ' CAPTURE THIS TEXT\n CAPTURE THIS TEXT\n', ' CAPTURE THIS TEXT\n\n', '\nCAPTURE THIS TEXT\nCAPTURE THIS TEXT\nCAPTURE THIS TEXT\nCAPTURE THIS TEXT\n\n', '']
要学习 pyparsing
的概念是每个子表达式独立运行,不知道任何包含或跟随的表达式。因此,当您的 line
要匹配一个或多个 "skip to the end of the current line" 时,它不知道在看到下一个 "Keyword" 字符串时应该停止,因此它可以预见地读取到字符串。然后,当解析器继续寻找 "Keyword 2:" 时,它已经超过了那个点,因此引发异常。
您需要告诉 OneOrMore
如果它在行的开头找到 "Keyword" 就应该停止解析,即使这通常会匹配重复的表达式。如果在一行的开头发现单词 "Keyword" ,则块结尾的合理检测可能是。 (您可以使其更详细并匹配 "Keyword" + integer + ":"
以使其真正防弹。)我们称其为 "start_of_block_marker":
start_of_block_marker = LineStart() + "Keyword"
要告诉 OneOrMore 这表示其重复的停止条件,请将此表达式作为 stopOn
参数传递:
line = OneOrMore(Group(SkipTo(LineEnd()) + EOL),
stopOn=LineStart() + "Keyword")
现在这将解析您的所有字符串,但您在 OneOrMore 中进行分组,而我认为您确实希望将所有子字符串放在一个组中。此外,2 和 3 之间的空行会创建一个额外的空行。这是行的改进版本:
line = Optional(EOL) + Group(OneOrMore(SkipTo(LineEnd()) + EOL,
stopOn=LineStart() + "Keyword"))
我将你的两个测试字符串放在一个列表中,然后将其作为参数 runTests()
:
text1 = """\
Keyword 1: CAPTURE THIS TEXT
CAPTURE THIS TEXT
Keyword 2: CAPTURE THIS TEXT
Keyword 3:
CAPTURE THIS TEXT
CAPTURE THIS TEXT
CAPTURE THIS TEXT
CAPTURE THIS TEXT
Keyword 4"""
text2 = """\
Keyword 1: CAPTURE THIS TEXT
Keyword 2: CAPTURE THIS TEXT
Keyword 3:
CAPTURE THIS TEXT
CAPTURE THIS TEXT
CAPTURE THIS TEXT
Keyword 4
"""
KEYWORD_CAPTURE_AREA.runTests(tests)
打印(回显每个测试,然后打印解析结果):
Keyword 1: CAPTURE THIS TEXT
CAPTURE THIS TEXT
Keyword 2: CAPTURE THIS TEXT
Keyword 3:
CAPTURE THIS TEXT
CAPTURE THIS TEXT
CAPTURE THIS TEXT
CAPTURE THIS TEXT
Keyword 4
[['CAPTURE THIS TEXT', 'CAPTURE THIS TEXT'], ['CAPTURE THIS TEXT'], ['CAPTURE THIS TEXT', 'CAPTURE THIS TEXT', 'CAPTURE THIS TEXT', 'CAPTURE THIS TEXT']]
[0]:
['CAPTURE THIS TEXT', 'CAPTURE THIS TEXT']
[1]:
['CAPTURE THIS TEXT']
[2]:
['CAPTURE THIS TEXT', 'CAPTURE THIS TEXT', 'CAPTURE THIS TEXT', 'CAPTURE THIS TEXT']
Keyword 1: CAPTURE THIS TEXT
Keyword 2: CAPTURE THIS TEXT
Keyword 3:
CAPTURE THIS TEXT
CAPTURE THIS TEXT
CAPTURE THIS TEXT
Keyword 4
[['CAPTURE THIS TEXT'], ['CAPTURE THIS TEXT'], ['CAPTURE THIS TEXT', 'CAPTURE THIS TEXT', 'CAPTURE THIS TEXT']]
[0]:
['CAPTURE THIS TEXT']
[1]:
['CAPTURE THIS TEXT']
[2]:
['CAPTURE THIS TEXT', 'CAPTURE THIS TEXT', 'CAPTURE THIS TEXT']
如果结果有错误,runTests()
会显示问题行和位置,并给出pyparsing
错误信息。
正在尝试分析多行文档中的多项选择。想要捕获每个关键字之间的所有行。这是一个例子:
Keyword 1: CAPTURE THIS TEXT
Keyword 2: CAPTURE THIS TEXT
Keyword 3:
CAPTURE THIS TEXT
CAPTURE THIS TEXT
CAPTURE THIS TEXT
Keyword 4
我可能也有
Keyword 1: CAPTURE THIS TEXT
CAPTURE THIS TEXT
Keyword 2: CAPTURE THIS TEXT
Keyword 3:
CAPTURE THIS TEXT
CAPTURE THIS TEXT
CAPTURE THIS TEXT
CAPTURE THIS TEXT
Keyword 4
我的代码看起来像
from pyparsing import *
EOL = LineEnd().suppress()
line = OneOrMore(Group(SkipTo(LineEnd()) + EOL))
KEYWORD_CAPTURE_AREA = Keyword("Keyword 1:").suppress() + line + Keyword("Keyword 2:").suppress() + line \
+ Keyword("Keyword 3:").suppress() + line + Keyword("Keyword 4").suppress()
当前方法 returns 如果我的结果跨越多行,则没有结果。假设应该有一个直接的解决方案 - 只是还没有找到它。
一定要pyparsing
吗?
如果没有,您可以使用拆分,例如
f = open('sample.txt')
values = []
for text in f.read().split('Keyword '):
values.append(text[2:])
print(values)
>> ['', ' CAPTURE THIS TEXT\n CAPTURE THIS TEXT\n', ' CAPTURE THIS TEXT\n\n', '\nCAPTURE THIS TEXT\nCAPTURE THIS TEXT\nCAPTURE THIS TEXT\nCAPTURE THIS TEXT\n\n', '']
要学习 pyparsing
的概念是每个子表达式独立运行,不知道任何包含或跟随的表达式。因此,当您的 line
要匹配一个或多个 "skip to the end of the current line" 时,它不知道在看到下一个 "Keyword" 字符串时应该停止,因此它可以预见地读取到字符串。然后,当解析器继续寻找 "Keyword 2:" 时,它已经超过了那个点,因此引发异常。
您需要告诉 OneOrMore
如果它在行的开头找到 "Keyword" 就应该停止解析,即使这通常会匹配重复的表达式。如果在一行的开头发现单词 "Keyword" ,则块结尾的合理检测可能是。 (您可以使其更详细并匹配 "Keyword" + integer + ":"
以使其真正防弹。)我们称其为 "start_of_block_marker":
start_of_block_marker = LineStart() + "Keyword"
要告诉 OneOrMore 这表示其重复的停止条件,请将此表达式作为 stopOn
参数传递:
line = OneOrMore(Group(SkipTo(LineEnd()) + EOL),
stopOn=LineStart() + "Keyword")
现在这将解析您的所有字符串,但您在 OneOrMore 中进行分组,而我认为您确实希望将所有子字符串放在一个组中。此外,2 和 3 之间的空行会创建一个额外的空行。这是行的改进版本:
line = Optional(EOL) + Group(OneOrMore(SkipTo(LineEnd()) + EOL,
stopOn=LineStart() + "Keyword"))
我将你的两个测试字符串放在一个列表中,然后将其作为参数 runTests()
:
text1 = """\
Keyword 1: CAPTURE THIS TEXT
CAPTURE THIS TEXT
Keyword 2: CAPTURE THIS TEXT
Keyword 3:
CAPTURE THIS TEXT
CAPTURE THIS TEXT
CAPTURE THIS TEXT
CAPTURE THIS TEXT
Keyword 4"""
text2 = """\
Keyword 1: CAPTURE THIS TEXT
Keyword 2: CAPTURE THIS TEXT
Keyword 3:
CAPTURE THIS TEXT
CAPTURE THIS TEXT
CAPTURE THIS TEXT
Keyword 4
"""
KEYWORD_CAPTURE_AREA.runTests(tests)
打印(回显每个测试,然后打印解析结果):
Keyword 1: CAPTURE THIS TEXT
CAPTURE THIS TEXT
Keyword 2: CAPTURE THIS TEXT
Keyword 3:
CAPTURE THIS TEXT
CAPTURE THIS TEXT
CAPTURE THIS TEXT
CAPTURE THIS TEXT
Keyword 4
[['CAPTURE THIS TEXT', 'CAPTURE THIS TEXT'], ['CAPTURE THIS TEXT'], ['CAPTURE THIS TEXT', 'CAPTURE THIS TEXT', 'CAPTURE THIS TEXT', 'CAPTURE THIS TEXT']]
[0]:
['CAPTURE THIS TEXT', 'CAPTURE THIS TEXT']
[1]:
['CAPTURE THIS TEXT']
[2]:
['CAPTURE THIS TEXT', 'CAPTURE THIS TEXT', 'CAPTURE THIS TEXT', 'CAPTURE THIS TEXT']
Keyword 1: CAPTURE THIS TEXT
Keyword 2: CAPTURE THIS TEXT
Keyword 3:
CAPTURE THIS TEXT
CAPTURE THIS TEXT
CAPTURE THIS TEXT
Keyword 4
[['CAPTURE THIS TEXT'], ['CAPTURE THIS TEXT'], ['CAPTURE THIS TEXT', 'CAPTURE THIS TEXT', 'CAPTURE THIS TEXT']]
[0]:
['CAPTURE THIS TEXT']
[1]:
['CAPTURE THIS TEXT']
[2]:
['CAPTURE THIS TEXT', 'CAPTURE THIS TEXT', 'CAPTURE THIS TEXT']
如果结果有错误,runTests()
会显示问题行和位置,并给出pyparsing
错误信息。