用于搜索和替换大字符串的最快Python方法

cyr*_*rus 14 python regex

我正在寻找最快的方法来替换非常大的字符串中的大量子字符串.这是我用过的两个例子.

findall()感觉更简单,更优雅,但需要花费大量时间.

finditer()通过一个大文件,但我不确定这是正确的方法.

这是一些示例代码.请注意,我感兴趣的实际文本是一个大小约10MB的单个字符串,这两种方法有很大的不同.

import re

def findall_replace(text, reg, rep):
    for match in reg.findall(text):
        output = text.replace(match, rep)
    return output

def finditer_replace(text, reg, rep):
    cursor_pos = 0
    output = ''
    for match in reg.finditer(text):
        output += "".join([text[cursor_pos:match.start(1)], rep])
        cursor_pos = match.end(1)
    output += "".join([text[cursor_pos:]])
    return output

reg = re.compile(r'(dog)')
rep = 'cat'
text = 'dog cat dog cat dog cat'

finditer_replace(text, reg, rep)

findall_replace(text, reg, rep)
Run Code Online (Sandbox Code Playgroud)

更新为测试添加了re.sub方法:

def sub_replace(reg, rep, text):
    output = re.sub(reg, rep, text)
    return output
Run Code Online (Sandbox Code Playgroud)

结果

re.sub() - 0:00:00.031000
finditer() - 0:00:00.109000
findall() - 0:01:17.260000

bti*_*lly 18

标准方法是使用内置的

re.sub(reg, rep, text)
Run Code Online (Sandbox Code Playgroud)

顺便提一下,您的版本之间性能差异的原因是第一个版本中的每个替换都会导致整个字符串被重新复制.副本速度很快,但是当您一次复制10 MB时,足够的副本将变得很慢.


eyq*_*uem 5

您可以,而且我认为您必须使用它,因为它肯定是一项优化功能

re.sub(pattern, repl, string[, count, flags])
Run Code Online (Sandbox Code Playgroud)

之所以你findall_replace()函数是长是在每场比赛中,创建一个新的字符串对象,你会通过执行以下代码见:

ch = '''qskfg qmohb561687ipuygvnjoihi2576871987uuiazpoieiohoihnoipoioh
opuihbavarfgvipauhbi277auhpuitchpanbiuhbvtaoi541987ujptoihbepoihvpoezi 
abtvar473727tta aat tvatbvatzeouithvbop772iezubiuvpzhbepuv454524522ueh'''

import re

def findall_replace(text, reg, rep):
    for match in reg.findall(text):
        text = text.replace(match, rep)
        print id(text)
    return text

pat = re.compile('\d+')
rep = 'AAAAAAA'

print id(ch)
print
print findall_replace(ch, pat, rep)
Run Code Online (Sandbox Code Playgroud)

请注意,在此代码中,我被替换output = text.replace(match, rep)text = text.replace(match, rep),否则仅替换最后一次出现的。

finditer_replace()很长,其原因与findall_replace()相同:重复创建字符串对象。但是前者使用迭代器re.finditer(),而后者则是通过构造列表对象而创建的,因此它更长。那就是迭代器和非迭代器之间的区别。