Производительность регулярных выражений в Python: лучший способ перебирать тексты с тысячами регулярных выражений - PullRequest
0 голосов
/ 21 октября 2019

Я много исследовал, но не нашел ничего, что действительно помогло бы мне. Может быть, мой подход просто странный - может быть, кто-то может направить мои мысли в правильном направлении.

Итак, вот такая ситуация:

Мне нужно обработать большое количество текстов (сотни тысяч). В этих текстах мне нужно найти и обработать определенные строки:

  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)
    

    Каждая идея высоко ценится!

1 Ответ

2 голосов
/ 21 октября 2019

Я не могу комментировать, но только некоторые мысли:

Из того, что вы опубликовали, похоже, что материал, который вы хотите искать, всегда одинаков, поэтому почему бы просто не присоединиться к нимв большом регулярном выражении и скомпилируйте это большое регулярное выражение перед запуском цикла.

Таким образом, вы не компилируете регулярное выражение для каждой итерации, а только один раз.

например

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...