【问题标题】:Speed up a series of regex replacement in python加速python中的一系列正则表达式替换
【发布时间】:2025-11-26 18:25:01
【问题描述】:

我的 python 脚本会读取文件中的每一行,并在每一行中进行许多正则表达式替换。

如果正则表达式成功,跳到下一行

有什么方法可以加快这种脚本的速度吗?
是否值得改为调用 subn 并检查替换是否完成然后跳到剩下的那个?
如果我编译正则表达式,是否可以将所有编译的正则表达式存储在内存中?

for file in files:  
     for line in file:  
         re.sub() # <--- ~ 100 re.sub

PS:每个正则表达式的替换变量

【问题讨论】:

  • 你编译正则表达式了吗?
  • 你应该展示你的代码(或一个简化的例子)——它会让你在做什么更清楚,并指出可以加快什么。
  • 我发现一些帖子说 python 实际上会编译正则表达式并缓存它。顺便说一句,我有近 100 个正则表达式,是否真的可以存储所有编译表达式。
  • Python 会缓存最近使用的正则表达式的编译版本,但数量有限。我认为 100 太多了,你应该编译正则表达式并将它们放在一个列表中。
  • 你在解析什么大小的文件?多少个文件?你应该看看这篇关于正则表达式时间复杂度的帖子:*.com/questions/4378455/…。如果你真的要执行那么多正则表达式,那么对于单个字符串匹配,最坏情况的时间是 O(n)。知道了这一点,您可能会考虑解析文件或线程化应用程序的替代方法?另请查看:swtch.com/~rsc/regexp/regexp1.html

标签: python regex


【解决方案1】:

你应该做三件事:

  1. 减少正则表达式的数量。根据替换部分的不同,您可以将它们全部组合成一个。通过仔细交替,您可以确定匹配正则表达式部分的顺序。
  2. 如果可能(取决于文件大小),请将文件完全读入内存。
  3. 编译您的正则表达式(仅是为了可读性;只要正则表达式的数量保持在 100 以下,速度就无关紧要)。

这会给你类似的东西:

regex = re.compile(r"My big honking regex")
for datafile in files:
    content = datafile.read()
    result = regex.sub("Replacement", content)

【讨论】:

  • 但是如果我将所有正则表达式连接成一个,我就不能为每个正则表达式指定特定的替换,对吧?
  • @Bear:这取决于您要替换的内容。请举例说明你在做什么。
  • 您实际上不需要将datafile.read() 分配给content,因为它只使用一次- 直接使用它可能会带来较小的性能优势。您还可以通过为 files - ibm.com/developerworks/library/l-pycon/index.html 创建 Python 迭代器来节省内存
  • @AaronNewton:肯定不会有可衡量的性能优势。在这种情况下,我更喜欢稍长、更明确的版本。
  • 对不起,这是真的。但是[regex.sub("Replacement", datafile.read()) for datafile in files] 呢?尽管许多人似乎认为列表理解不一定更快,或者如果您不想要列表很有用forums.xkcd.com/viewtopic.php?f=11&t=54443
【解决方案2】:

正如@Tim Pietzcker 所说,您可以通过使它们成为替代品来减少正则表达式的数量。您可以通过使用匹配对象的 'lastindex' 属性来确定哪个替代匹配。

这是您可以做的一个示例:

>>> import re
>>> replacements = {1: "<UPPERCASE LETTERS>", 2: "<lowercase letters>", 3: "<Digits>"}
>>> def replace(m):
...     return replacements[m.lastindex]
...
>>> re.sub(r"([A-Z]+)|([a-z]+)|([0-9]+)", replace, "ABC def 789")
'<UPPERCASE LETTERS> <lowercase letters> <Digits>'

【讨论】:

  • replacements = [None, "&lt;UPPERCASE LETTERS&gt;", "&lt;lowercase letters&gt;", "&lt;Digits&gt;"] 也可以。
最近更新 更多