我有一个字符串,可以通过以下(预期的额外空间)说明:
"words that don't matter START some words one some words two some words three END words that don't matter"
为了获取START和END ['some words one', some words two', 'some words three']
之间的每个子字符串,我编写了以下代码:
result = re.search(r'(?<=START).*?(?=END)', string, flags=re.S).group()
result = re.findall(r'(\(?\w+(?:\s\w+)*\)?)', result)
是否可以通过一个正则表达式来实现这一目标?
答案 0 :(得分:2)
从理论上讲,你可以将你的第二个正则表达式包装在()*
中并将其放入第一个正则表达式中。这将捕获您在边界中出现的所有内部表达式。不幸的是,Python实现只保留了多次匹配的组的最后一个匹配。我知道保留组中所有匹配项的唯一实现是.NET。所以很遗憾不适合你的解决方案。
另一方面,为什么你不能简单地采用你所采用的两步法?
编辑: 您可以使用在线正则表达式工具比较我描述的行为。
模式:(\w+\s*)*
输入:aaa bbb ccc
以https://pythex.org/和http://regexstorm.net/tester为例。
您将看到Python返回一个匹配/组ccc
,而.NET返回$1
,因为三个捕获 aaa, bbb, ccc
。
Edit2:正如@Jan所说,还有更新的regex
模块支持多次捕获。我完全忘记了这一点。
答案 1 :(得分:1)
使用较新的regex
模块,您可以一步完成:
(?:\G(?!\A)|START)\s*\K
(?!\bEND\b)
\w+\s+\w+\s+\w+
<小时/> 这看起来很复杂,但是细分了,它说:
(?:\G(?!\A)|START) # look for START or the end of the last match
\s*\K # whitespaces, \K "forgets" all characters to the left
(?!\bEND\b) # neg. lookahead, do not overrun END
\w+\s+\w+\s+\w+ # your original expression
<小时/> 在
Python
中,这看起来像是:
import regex as re
rx = re.compile(r'''
(?:\G(?!\A)|START)\s*\K
(?!\bEND\b)
\w+\s+\w+\s+\w+''', re.VERBOSE)
string = "words that don't matter START some words one some words two some words three END words that don't matter"
print(rx.findall(string))
# ['some words one', 'some words two', 'some words three']
<小时/> 另请参阅a demo on regex101.com。
答案 2 :(得分:0)
这是一个理想的情况,我们可以使用re.split
,如提到的@PeterE来规避只能访问最后捕获的组的问题。
import re
s=r'"words that don\'t matter START some words one some words two some words three END words that don\'t matter" START abc a bc c END'
print('\n'.join(re.split(r'^.*?START\s+|\s+END.*?START\s+|\s+END.*?$|\s{2,}',s)[1:-1]))
在我们使用re.MULTILINE
和re.M
时启用^
/ $
标记。
<强> 输出 强>
some words one
some words two
some words three
abc
a bc c