使用python regex匹配所有可能的1,2,3和4个单词组

时间:2014-07-17 02:15:29

标签: python regex string

如何使用python正则表达式匹配字符串中1,2,3和4个单词的所有可能序列?所有序列必须仅包含相邻的单词。所以:

str1 = 'AA BB CC DD EE FF GG HH'
matches = re.findall(r'insert ninja regex here', str1)
for match in matches:
    print match

应输出:

AA
AA BB
BB
AA BB CC
BB CC
CC
AA BB CC DD
BB CC DD
CC DD
DD
BB CC DD EE
CC DD EE
DD EE
EE
... etc etc

由于

有四个正则表达式的可能解决方案(如果您有更高效,更快捷的方法,请告诉我):

matches4 = re.findall(r'(?=((?:\s\S+){3}\s\S+))', str1)
matches3 = re.findall(r'(?=((?:\s\S+){2}\s\S+))', str1)
matches2 = re.findall(r'(?=((?:\s\S+){1}\s\S+))', str1)
matches1 = re.findall(r'(?=(\s\S+))', str1)

结果如下:

I ran all 4 answers on a string with 138.2k characters and 22.2k words:
my answer=0.0856201648712s.
zx81 answer option 1=0.0598151683807s.
zx81 answer option 2=0.0905468463898s.
Greg Hewgill answer=0.0292818546295s.

获胜者是GREG!但是,zx81可以获得正则表达式解决方案的答案。你们都投票了。

3 个答案:

答案 0 :(得分:4)

您可以在不使用任何正则表达式的情况下执行此操作,并且这样做可能更容易。

>>> str1 = 'AA BB CC DD EE FF GG HH'
>>> a = str1.split()
>>> [" ".join(a[i:i+n]) for n in range(1, 5) for i in range(len(a)-n+1)]
['AA', 'BB', 'CC', 'DD', 'EE', 'FF', 'GG', 'HH', 'AA BB', 'BB CC', 'CC DD', 'DD EE', 'EE FF', 'FF GG', 'GG HH', 'AA BB CC', 'BB CC DD', 'CC DD EE', 'DD EE FF', 'EE FF GG', 'FF GG HH', 'AA BB CC DD', 'BB CC DD EE', 'CC DD EE FF', 'DD EE FF GG', 'EE FF GG HH']

在任何情况下,它都比任何正则表达式更容易阅读。

答案 1 :(得分:4)

重叠匹配:Lookahead Trickery

可以将所有组合与单个正则表达式匹配。由于匹配重叠,我们将使用前瞻和可选的捕获组。

以下是两个选项。

选项1:较短的正则表达式,未排序的输出

(?=((((\b\S+)(?: \S+)?)(?: \S+)?)(?: \S+)?))

所有组合都被捕获到各种比赛的第1,2,3和4组。当我们将所有小组组合成一组时,会消除一些欺骗。在the regex demo中,请查看右下方窗格中的群组捕获。

示例代码

import re
subject = "AA BB CC DD EE FF GG HH"
reobj = re.compile(r"(?=((((\b\S+)(?: \S+)?)(?: \S+)?)(?: \S+)?))")
result = reobj.findall(subject)
tokens = set()
for a in result:
    for b in a:
        tokens.add(b)
print(tokens)        

<强>输出

{'CC DD EE', 'EE FF GG HH', 'GG', 'DD EE FF',
'FF', 'DD EE FF GG', 'BB CC DD', 'DD EE', 'FF GG',
'CC', 'FF GG HH', 'HH', 'EE FF GG', 'AA BB', 'CC DD',
'AA BB CC', 'DD', 'GG HH', 'AA', 'BB CC DD EE', 
'EE FF', 'EE', 'AA BB CC DD', 'BB', 'BB CC', 
'CC DD EE FF'}

选项2:更长的正则表达式,分类输出

(?=\b(\S+(?: \S+){3}))?(?=\b(\S+(?: \S+){2}))?(?=\b(\S+ \S+))?(?=(\b\S+))

当我们构建列表时,需要删除一些空字符串。

示例代码

import re
subject = "AA BB CC DD EE FF GG HH"
reobj = re.compile(r"(?=(\b\S+))(?=\b(\S+ \S+))?(?=\b(\S+(?: \S+){2}))?(?=\b(\S+(?: \S+){3}))?")
result = reobj.findall(subject)
tokens = []
for a in result:
    for b in a:
        if b != "":
            tokens.append(b)
print(tokens)        

<强>输出

['AA', 'AA BB', 'AA BB CC', 'AA BB CC DD', 
 'BB', 'BB CC', 'BB CC DD', 'BB CC DD EE',
 'CC', 'CC DD', 'CC DD EE', 'CC DD EE FF', 
 'DD', 'DD EE', 'DD EE FF', 'DD EE FF GG',
 'EE', 'EE FF', 'EE FF GG', 'EE FF GG HH', 
 'FF', 'FF GG', 'FF GG HH', 
 'GG', 'GG HH', 
 'HH']

答案 2 :(得分:0)

效率很高 - 有四个正则表达式的解决方案(如果你有更高效,更快捷的方法,请告诉我):

matches4 = re.findall(r'(?=((?:\s\S+){3}\s\S+))', str1)
matches3 = re.findall(r'(?=((?:\s\S+){2}\s\S+))', str1)
matches2 = re.findall(r'(?=((?:\s\S+){1}\s\S+))', str1)
matches1 = re.findall(r'(?=(\s\S+))', str1)