Для замены длинного регулярного выражения требуется несколько проходов - почему? - PullRequest
0 голосов
/ 13 февраля 2019

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

Так что у меня есть длинное регулярное выражение - ничего сложного, просто куча простых условий.Я использую его для удаления переданных по конвейеру слов из начала и конца именованных сущностей, которые я извлек из данных новостных статей.Вариант использования: у многих имен есть эти короткие слова (например, Центры по контролю и профилактике заболеваний), но я хочу удалить слова, когда они появляются в начале или в конце имени.Например, я не хочу, чтобы «Центры по контролю за заболеваниями» учитывались иначе, чем « Центры по контролю за заболеваниями» по очевидным причинам.

Я использовал эту строку регулярного выражения в большом (> 1M) списке именованных сущностей в Python 3.7.2, используя следующий код ( file здесь ):

with open('pnames.csv','r') as f:
    named_entities = f.read().splitlines()

print(len([i for i in named_entities if i == 'the wall street journal']))
# 146

short_words = "^and\s|\sand$|^at\s|\sat$|^by\s|\sby$|^for\s|\sfor$|^in\s|\sin$|^of\s|\sof$|^on\s|\son$|^the\s|\sthe$|^to\s|\sto$"

cleaned_entities = [re.sub(short_words,"",i) 
for i 
in named_entities]

print(len([i for i in cleaned_entities 
if i == 'the wall street journal']))
# 80 (huh, should be 0. Let me try again...)

cleaned_entities2 = [re.sub(short_words,"",i) 
for i 
in cleaned_entities]

print(len([i for i in cleaned_entities2 
if i == 'the wall street journal']))
# 1 (better, but still unexpected. One more time...)

cleaned_entities3 = [re.sub(short_words,"",i) 
for i 
in cleaned_entities2]

print(len([i for i in cleaned_entities3 
if i == 'the wall street journal']))
# 0 (this is what I expected on the first run!)

Мой вопрос: почему регулярное выражение не удаляет все подходящие подстроки за один проход?то есть, почему len([i for i in cleaned_entities if i == 'the wall street journal']) не равно 0?Почему для выполнения задания требуется несколько запусков?

То, что я пробовал:

  • Перезапуск Spyder
  • Запуск того же кода в Python 3.7.2,Python 3.6.2 и эквивалентный код в R 3.4.2 (Питоны дали точно такие же результаты, а R дал разные числа, но мне все равно пришлось запустить его несколько раз, чтобы добраться до нуля)
  • Запуск кодатолько для подстрок, соответствующих регулярному выражению (тот же результат)
  • Запуск кода только для строк, равных «журналу Уолл-стрит» (работает за один проход)
  • Подстановка регулярного выражения "^the " в приведенном выше коде (исправляет все совпадения за один проход)

Так что да, любые идеи будут полезны.

1 Ответ

0 голосов
/ 14 февраля 2019

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

and and at by in of the the wall street journal at the by on the

, потребовалось бы много проходов, чтобы полностью удалить все.

Выражение можно изменить, чтобы использовать + для обозначения одного илидругие случаи:

import re

with open('pnames2.csv','r') as f:
    named_entities = f.read().splitlines()

print(len([i for i in named_entities if i == 'the wall street journal']))
# 146

short_words = "^((and|at|by|for|in|of|on|the|to)\s)+|(\s(and|at|by|for|in|of|on|the|to))+$"
re_sw = re.compile(short_words)

cleaned_entities = [re_sw.sub("", i) for i in named_entities]

print(len([i for i in cleaned_entities if i == 'the wall street journal']))
# 0

Процесс можно немного ускорить, предварительно скомпилировав регулярное выражение.Было бы еще быстрее, если бы вы применили его ко всему файлу, а не применяли его построчно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...