Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Python中查找与正则表达式匹配的所有(包括重叠)子字符串_Python_Regex_Performance - Fatal编程技术网

在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(我也需要使用lookbehinds)。例如,模式
(?好吧,你在问题中没有指定这一点,是吗?但是如果你需要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)]
。同意。对于具有可选贪婪匹配的正则表达式,该解决方案是次优的。