【问题标题】:Efficient way to do a large number of search/replaces in Python?在 Python 中进行大量搜索/替换的有效方法?
【发布时间】:2011-01-12 06:52:07
【问题描述】:

我对 Python 还很陌生,正在编写一系列脚本来在一些专有标记格式之间进行转换。我在文件上逐行迭代,然后基本上做了大量(100-200)的替换,基本上分为 4 类:

line = line.replace("-","<EMDASH>")  # Replace single character with tag
line = line.replace("<\\@>","@")     # tag with single character
line = line.replace("<\\n>","")      # remove tag
line = line.replace("\xe1","&bull;") # replace non-ascii character with entity

str.replace() 函数似乎非常有效(当我检查分析输出时,数字相当低),但有没有更好的方法来做到这一点?我见过以函数作为参数的 re.sub() 方法,但不确定这是否会更好?我想这取决于 Python 在内部做了什么样的优化。以为我会在创建可能不是很有帮助的大型字典之前征求一些建议!

此外,我还对标签进行了一些解析(看起来有点像 HTML,但不是 HTML)。我识别这样的标签:

m = re.findall('(<[^>]+>)',line)

然后在匹配的标签中也进行约 100 次搜索/替换(主要是删除匹配项),例如:

m = re.findall('(<[^>]+>)',line)
for tag in m:
    tag_new = re.sub("\*t\([^\)]*\)","",tag)
    tag_new = re.sub("\*p\([^\)]*\)","",tag_new)

    # do many more searches...

if tag != tag_new:
    line = line.replace(tag,tag_new,1) # potentially problematic

这里有什么关于效率的想法吗?

谢谢!

【问题讨论】:

    标签: python regex


    【解决方案1】:

    str.replace() 如果您要进行基本的搜索和替换,效率会更高,如果您需要复杂的模式匹配,re.sub(显然)会更有效(因为否则您必须使用 str.replace 几个次)。

    我建议您将两者结合使用。如果您有多个模式都被一件事所取代,请使用re.sub。如果您只是在某些情况下只需要将一个特定标签替换为另一个,请使用str.replace

    您还可以通过使用更大的字符串来提高效率(调用re.sub 一次,而不是每行一次)。增加内存使用,但除非文件很大,否则应该不是问题,而且还可以缩短执行时间。

    【讨论】:

      【解决方案2】:

      如果您实际上不需要正则表达式并且只是进行文字替换,那么 string.replace() 几乎肯定会更快。但即便如此,您的瓶颈将是文件输入/输出,而不是字符串操作。

      最好的解决方案可能是使用cStringIO

      【讨论】:

        【解决方案3】:

        根据您正在操作的文本的相关部分与不相关部分的比例(以及每个替换操作的部分是否重叠),尝试分解输入可能更有效放入令牌并单独处理每个令牌。

        由于当前实现中的每个 replace() 都必须检查整个输入字符串,这可能会很慢。如果你改为将该流分解成类似...

        [<normal text>, <tag>, <tag>, <normal text>, <tag>, <normal text>]
        # from an original "<normal text><tag><tag><normal text><tag><normal text>"
        

        ...那么您可以简单地查看给定的标记是否是一个标签,然后在列表中替换它(然后在最后''.join())。

        【讨论】:

          【解决方案4】:

          您可以将函数对象传递给re.sub而不是替换字符串,它接受匹配对象并返回替换,例如

          >>> r = re.compile(r'<(\w+)>|(-)')
          >>> r.sub(lambda m: '(%s)' % (m.group(1) if m.group(1) else 'emdash'), '<atag>-<anothertag>')
          '(atag)(emdash)(anothertag)'
          

          当然你可以使用更复杂的函数对象,这个 lambda 只是一个例子。

          使用单个正则表达式完成所有替换应该比多次迭代字符串稍快,但如果执行大量替换,调用计算替换的函数对象的开销可能会很大。

          【讨论】:

            猜你喜欢
            • 2013-07-11
            • 2022-01-14
            • 2014-04-11
            • 1970-01-01
            • 1970-01-01
            • 2011-08-07
            • 1970-01-01
            • 2011-02-11
            • 1970-01-01
            相关资源
            最近更新 更多