Регулярное выражение Python для подсчета нескольких совпадающих строк в предложениях

Я пытаюсь получить количество шаблонов, сгенерированных из строки hello awesome world, найденной в большом тексте. Шаблоны генерируются путем перестановки слов и замены одного слова на * между ними. В этом примере я использую только 4 шаблона для упрощения. Я не совсем знаком с регулярными выражениями, поэтому мой код еще не соответствует всему, что мне нужно. Я, вероятно, скоро разберусь с этим, но я не уверен, будет ли он хорошо масштабироваться, когда я подаю реальные данные.

Вопросы заключаются в том, как мне исправить мой код и есть ли лучшие/более быстрые способы достижения моей цели? Вот мой код ниже с пояснениями.

import re
from collections import Counter


# Input text. Could consist of hundreds of thousands of sentences.
txt = """
Lorèm ipsum WORLD dolor AWESOME sit amèt, consectetur adipiscing elit. 
Duis id AWESOME HELLO lorem metus. Pràesent molestie malesuada finibus. 
Morbi non èx a WORLD HELLO AWESOME erat bibendum rhoncus. Quisque sit 
ametnibh cursus, tempor mi et, sodàles neque. Nunc dapibus vitae ligula at porta. 
Quisque sit amet màgna eù sem sagittis dignissim et non leo. 
Quisque WORLD, AWESOME dapibus et vèlit tristique tristique. Sed 
efficitur dui tincidunt, aliquet lèo eget, pellentesque felis. Donec 
venenatis elit ac aliquet varius. Vestibulum ante ipsum primis in faucibus
orci luctus et ultrices posuere cubilia Curae. Vestibulum sed ligula 
gravida, commodo neque at, mattis urna. Duis nisl neque, sollicitudin nec 
mauris sit amet, euismod semper massa. Curabitur sodales ultrices nibh, 
ut ultrices ante maximus sed. Donec rutrum libero in turpis gravida 
dignissim. Suspendisse potenti. Praesent eu tempor quam, id dictum felis. 
Nullam aliquam molestie tortor, at iaculis metus volutpat et. In dolor 
lacus, AWESOME sip HELLO volutpat ac convallis non, pulvinar eu massa.
"""

txt = txt.lower()

# Patterns generated from a 1-8 word input string. Could also consist of hundreds of 
# thousands of patterns
patterns = [
    'world',
    'awesome',
    'awesome hello', 
    'world hello awesome',
    'world (.*?) awesome'   # '*' - represents any word between
]

regex = '|'.join(patterns)
result = re.findall(regex, txt)
counter = Counter(result)
print(counter)
# >>> Counter({'awesome': 5, 'world': 3})

# For some reason i can't get strings with more than one word to match

# Expected output
found_pattern_counts = {
    'world': 3,
    'awesome': 5,
    'awesome hello': 1, 
    'world hello awesome': 1,
    'world * awesome': 2
}
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
77
2

Ответы 2

Вы могли бы заглянуть в

re.finditer()

Итераторы сэкономят вам много ресурсов, если вам не нужны все данные сразу (что вы вряд ли когда-нибудь сделаете). Таким образом, вам не нужно хранить так много информации в памяти. Посмотрите на этот Экономят ли итераторы память в Python?

я посмотрю на это, но я все еще не могу сопоставить шаблоны с пробелом между ними. Я попытался заменить * на (.*?), чтобы получить «любое слово между шаблонами», но стало еще хуже.

Superbman 02.02.2019 21:29

Вы неправильно использовали подстановочный знак, я исправил это, и теперь он работает так, как вы описали, и теперь вы можете создать дополнительную функцию для этой операции:

patterns = [
    'world',
    'awesome',
    'awesome hello', 
    'world hello awesome',
    'world (.*?) awesome'
]


result = {} 
for pattern in patterns:
   rex = re.compile(fr'{pattern}') 
   count = len(rex.findall(txt))   
   result[pattern] = result.get(pattern, 0) + count

print(result)

круто, спасибо. Есть ли способ ускорить его? Когда я умножаю txt на 10 000 и увеличиваю количество шаблонов до 1000, он становится очень медленным - на завершение ушло 5 минут.

Superbman 02.02.2019 22:48

конечно, это будет медленно, регулярное выражение добавляет некоторые накладные расходы. Я думаю, что будет лучше использовать обычный строковый поиск («слово» в txt), где у вас нет подстановочных знаков.

EntGriff 02.02.2019 23:08

также см. эту статью: medium.freecodecamp.org/…

EntGriff 02.02.2019 23:09

Ничего себе, FlashText выглядит как то, что мне нужно, потому что в некоторых случаях количество шаблонов может достигать 1 000 000. Я собираюсь проверить это. Спасибо

Superbman 02.02.2019 23:14

EntGriff, я только что проверил это. Он не может обрабатывать перекрытия, а также не поддерживает подстановочные знаки, хотя он быстрый.

Superbman 02.02.2019 23:46

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

EntGriff 02.02.2019 23:50

это похоже на решение stackoverflow.com/questions/42742810/…, но проблема в том, что у меня есть несколько слов в шаблоне вместо одного мира.

Superbman 03.02.2019 00:00

Другие вопросы по теме