使用Python进行RegEx:在边界内查找

时间:2017-09-30 22:54:59

标签: python regex findall

我有一个字符串,可以通过以下(预期的额外空间)说明:

"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)

是否可以通过一个正则表达式来实现这一目标?

3 个答案:

答案 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.MULTILINEre.M时启用^ / $标记。

<强> 输出

some words one
some words two
some words three
abc
a bc c