正则表达式中任意顺序匹配所有字符
我刚接触正则表达式,但我知道怎么在正则查询中按顺序匹配任何字符,比如说 [abc] 可以匹配 a、b 或 c 中的任意一个。而且,我相信 "abc" 会精确匹配 abc。
不过,我想知道怎么构造一个正则查询,可以匹配 abc 这几个字符,不管它们的顺序是什么。所以比如说,我希望它能匹配 "cab" 或 "bracket"。我在用 Python 作为我的脚本语言(不确定这是否重要)。
3 个回答
2
这里是对 issubset 和 正则表达式 解决方案的时间比较。
import re
def using_lookahead(text):
pat=re.compile(r'^(?=.*a)(?=.*b)(?=.*c)')
return pat.search(text)
def using_set(text):
chars=set('abc')
return chars.issubset(text)
对于短字符串,issubset
可能会稍微快一点:
% python -mtimeit -s'import test' "test.using_set('bracket')"
100000 loops, best of 3: 2.63 usec per loop
% python -mtimeit -s'import test' "test.using_lookahead('bracket')"
100000 loops, best of 3: 2.87 usec per loop
但是对于长字符串,正则表达式明显更快:
当匹配结果出现得比较晚的时候:
% python -mtimeit -s'import test' "test.using_set('o'*1000+'bracket')" 10000 loops, best of 3: 49.7 usec per loop % python -mtimeit -s'import test' "test.using_lookahead('o'*1000+'bracket')" 100000 loops, best of 3: 6.66 usec per loop
当匹配结果出现得比较早的时候:
% python -mtimeit -s'import test' "test.using_set('bracket'+'o'*1000)" 10000 loops, best of 3: 50 usec per loop % python -mtimeit -s'import test' "test.using_lookahead('bracket'+'o'*1000)" 100000 loops, best of 3: 13.9 usec per loop
(为了回答评论中的一个问题:)可以使用 r'^(?=.*a)(?=.*b)(?=.*c)'
来表示要匹配的内容:
In [40]: pat=re.compile(r'^(?=.*a)(?=.*b)(?=.*c)')
In [41]: pat.search('bracket')
Out[41]: <_sre.SRE_Match object at 0x9f9a6b0>
12
这可以通过前瞻断言来实现:
^(?=.*a)(?=.*b)(?=.*c)
这个匹配规则会检查你的字符串中是否至少包含一次 a
、b
和 c
。
不过,正如你所看到的,这其实不是正则表达式擅长的事情。
我会这样做:
if all(char in mystr for char in "abc"):
# do something
检查速度:
>>> timeit.timeit(stmt='chars.issubset("bracket");chars.issubset("notinhere")',
... setup='chars=set("abc")')
1.3560583674019995
>>> timeit.timeit(stmt='all(char in "bracket" for char in s);all(char in "notinhere" for char in s)',
... setup='s="abc"')
1.4581878714681409
>>> timeit.timeit(stmt='r.match("bracket"); r.match("notinhere")',
... setup='import re; r=re.compile("(?=.*a)(?=.*b)(?=.*c)")')
1.0582279123082117
嘿,看看,正则表达式赢了!即使是对于更长的搜索字符串,这个结果也是成立的:
>>> timeit.timeit(stmt='chars.issubset("bracketed");chars.issubset("notinhere")',
... setup='chars=set("abcde")')
1.4316702294817105
>>> timeit.timeit(stmt='all(char in "bracketed" for char in s);all(char in "notinhere" for char in s)',
... setup='s="abcde"')
1.6696223364866682
>>> timeit.timeit(stmt='r.match("bracketed"); r.match("notinhere")',
... setup='import re; r=re.compile("(?=.*a)(?=.*b)(?=.*c)(?=.*d)(?:.*e)")')
1.1809254199004044
14
在Python中,我不会为了这个目的使用正则表达式,而是会用一个集合:
>>> chars = set("abc")
>>> chars.issubset("bracket")
True
>>> chars.issubset("fish")
False
>>> chars.issubset("bad")
False
正则表达式很有用,但在某些情况下,其他工具会更合适。