首页 > 解决方案 > Python 正则表达式性能:使用数千个正则表达式迭代文本的最佳方法

问题描述

我进行了很多研究,但没有找到任何真正帮助我的东西。也许我的方法很奇怪——也许有人可以让我的想法朝着正确的方向发展。

所以情况如下:

我需要处理大量文本(数十万)。在这些文本中,我需要查找和处理某些字符串:

  1. 我从数据库中提取的某些“静态”子字符串(如案例编号)(也有数十万个)
  2. 我与正则表达式匹配的字符串,该正则表达式动态构建以匹配每个可能出现的情况——正则表达式的最后一部分将被动态设置

很明显,这会导致大量的迭代,因为每个文本都需要输入一个函数来运行数十万个正则表达式——毕竟这会导致非常长的运行时间。

有没有更好更快的方法来完成所需的任务?现在完成的方式可以工作,但速度非常慢,并且会给服务器带来数周的沉重负载。

一些示例代码来说明我的想法:

import re

cases = []          # 100 000 case numbers from db
suffixes = []       #  500 diffrent suffixes to try from db

texts = []          # 100 000 for the beginning - will become less after initial run

def process_item(text: str) -> str:
    for s in suffixes:
        pattern = '(...)(.*?)(%s|...)' % s
        x = re.findall(pattern, text, re.IGNORECASE)
        for match in x:
            # process the matches, where I need to know which suffix matched
            pass
    for c in cases:
        escaped = re.escape(c)
        x = re.findall(escaped, text, re.IGNORECASE)
        for match in x:
            # process the matches, where I need to know which number matched
            pass

    return text


for text in texts:
    processed = process_item(text)

每个想法都受到高度赞赏!

标签: pythonregexpython-3.x

解决方案


我无法发表评论,但只是一些想法:

从您发布的内容来看,您想要搜索的东西总是相同的,所以为什么不将它们加入大正则表达式并在运行循环之前编译那个大正则表达式。

这样您就不必为每次迭代编译正则表达式,而只需编译一次。

例如

import re

cases = []          # 100 000 case numbers from db
suffixes = []       #  500 diffrent suffixes to try from db

texts = []          # 100 000 for the beginning - will become less after initial run

bre1 = re.compile('|'.join(suffixes), re.IGNORECASE)
bre2 = re.compile('|'.join([re.escape(c) for c in cases]), re.IGNORECASE)

def process_item(text: str) -> str:
    x = re.findall(bre1, text)
    for match in x:
        # process the matches, where I need to know which suffix matched
        pass

   x = re.findall(bre1, text)
   for match in x:
       # process the matches, where I need to know which number matched
       pass

    return text


for text in texts:
    processed = process_item(text)

如果您可以case number在其中可靠地找到text(例如,如果它之前有一些标识符),最好使用找到案例编号re.search并将案例编号放入set其中并测试该集合中的成员资格。

例如

cases = ["123", "234"]
cases_set = set(cases)

texts = ["id:123", "id:548"]

sre = re.compile(r'(?<=id:)\d{3}')
for t in texts:
    m = re.search(sre, t)
    if m and m.group() in cases_set:
        # do stuff ....
        pass

推荐阅读