在Python中查找与正则表达式匹配的所有(包括重叠)子字符串
我需要找到字符串中所有匹配正则表达式的子字符串的位置。例如,如果字符串是在Python中查找与正则表达式匹配的所有(包括重叠)子字符串,python,regex,performance,Python,Regex,Performance,我需要找到字符串中所有匹配正则表达式的子字符串的位置。例如,如果字符串是abbba,而regexp是(b | bb)(?=a),则结果应该是[(2,4)、(3,4)] 我想到的是 def get_ranges(模式:str,字符串:str)->list[tuple[int,int]: n=len(字符串) 返回[(开始,结束)范围内的开始(n+1)范围内的结束(开始,n+1) if re.fullmatch(f.{{{{start}}}({pattern})。{{{{n-end}},string
abbba
,而regexp是(b | bb)(?=a)
,则结果应该是[(2,4)、(3,4)]
我想到的是
def get_ranges(模式:str,字符串:str)->list[tuple[int,int]:
n=len(字符串)
返回[(开始,结束)范围内的开始(n+1)范围内的结束(开始,n+1)
if re.fullmatch(f.{{{{start}}}({pattern})。{{{{n-end}},string)]
但这往往执行得非常慢,特别是考虑到它不允许使用预编译的regexp。有没有更有效的方法来解决这个问题?首先,我认为您应该使用
来表示范围内的结束(开始,n+1)
。对于end
变量,我认为没有任何理由每次迭代都从0开始。通过这个编辑,执行这个代码
for i in range(300000):
get_ranges(r"(b|bb)(?=a)", "abbba")
我的时间从9.67秒到6.01秒。您可能想尝试稍微不同的正则表达式-
(b{1,2})(?=a)
,它应该稍微快一点
其次,您可以编译模式,并通过剪切字符串而不是正则表达式来使用它:
pattern = re.compile('(b{1,2})(?=a)')
def get_ranges(pattern: str, string: str):
result = []
start, end = 0, len(string)
match = pattern.search(string)
while match is not None and start < end:
result.append((match.start(0)+start, match.end(0)+start))
start += match.start(0) + 1
match = pattern.search(string[start:])
return result
pattern=re.compile(‘(b{1,2})(?=a)’)
def get_范围(模式:str,字符串:str):
结果=[]
开始,结束=0,长度(字符串)
匹配=模式。搜索(字符串)
当匹配不是无且开始<结束:
result.append((match.start(0)+start,match.end(0)+start))
开始+=匹配。开始(0)+1
match=pattern.search(字符串[start:])
返回结果
您还可以生成
,而不是在返回之前完整地构建结果
比较时间(每100万名执行人员):
- 原件:38.42 s
- 高于:2.14秒(17.95倍加速比)
版本:0.2914秒(131.85倍加速比)产量
(?好吧,你在问题中没有指定这一点,是吗?但是如果你需要lookbehinds,那么它在你的情况下确实不起作用。这似乎相当于只返回[m.span(1)for m in re.finditer(f'(?=({pattern})),string)]
@sophos这不仅仅是lookbehinds。简单b{1,2}
与字符串bb
匹配后,将返回[(0,2)、(1,2)]
而不是[(0,1)、(0,2)、(1,2)]
。同意。对于具有可选贪婪匹配的正则表达式,该解决方案是次优的。