Извлечение целых слов

#python #regex #word #alphabetical #text-extraction

#python #регулярное выражение #word #алфавитный #извлечение текста

Вопрос:

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

В настоящее время я извлекаю все алфавитные последовательности с помощью '[a-z] ' . Это хорошее приближение, но оно влечет за собой много мусора.

В идеале я бы хотел, чтобы какое-нибудь регулярное выражение (не обязательно должно быть красивым или эффективным) извлекало все алфавитные последовательности, разделенные естественными разделителями слов (такими [/-_,.: ] как и т.д.), и игнорировало любые алфавитные последовательности с недопустимыми границами.

Однако я также был бы рад просто иметь возможность получать все алфавитные последовательности, которые НЕ являются смежными с числом. Так, например, 'pie21' НЕ извлекал бы 'pie' , но 'http://foo.com' извлекал бы ['http', 'foo', 'com'] .

Я пробовал утверждения lookahead и lookbehind , но они применялись для каждого символа (так, например, re.findall('(?<!d)[a-z] (?!d)', 'pie21') возвращались 'pi' , когда я хочу, чтобы это ничего не возвращало). Я попытался обернуть альфа-часть как термин ( (?:[a-z] ) ), но это не помогло.

Подробнее: Данные представляют собой базу данных электронной почты, поэтому в основном это простой английский с обычными числами, но иногда встречаются ненужные строки вроде GIHQ4NWL0S5SCGBDD40ZXE5IDP13TYNEA и AC7A21C0 , которые я бы хотел полностью игнорировать. Я предполагаю, что любая алфавитная последовательность с числом в ней является мусором.

Комментарии:

1. Лучше использовать необработанные строки с регулярными выражениями. d случается, что работает, но другие escape-последовательности завершаются сбоем, и это может быть сложно отладить.

Ответ №1:

Если вы ограничиваетесь буквами ASCII, то используйте (с re.I установленным параметром)

 b[a-z] b
  

b является привязкой к границе слова, совпадающей только в начале и конце буквенно-цифровых «слов». Так b[a-z] b совпадает pie , но не pie21 или 21pie .

Чтобы также разрешить использование других букв, отличных от ASCII, вы можете использовать что-то вроде этого:

 b[^Wd_] b
  

который также допускает символы с ударением и т.д. Возможно, вам потребуется установить re.UNICODE параметр, особенно при использовании Python 2, чтобы w сокращение соответствовало буквам, отличным от ASCII.

[^Wd_] в качестве отрицаемого символьного класса допускается любой буквенно-цифровой символ, за исключением цифр и подчеркивания.

Комментарии:

1. Это звучит именно так, как я хочу, но я не могу заставить bally b работать. Если text задать как некоторое обычное предложение, re.findall('b[a-z] b', text, re.I) ничего не возвращает. Независимо от того, что я помещаю в квадратные скобки (или использую search или match ), это, похоже, тоже не помогает. Использование B дает мне некоторые результаты, но удаляет первый и последний символ каждого слова. Как бы лениво это ни звучало, я слишком устал, чтобы прямо сейчас изучать новую концепцию; есть шанс, что вы знаете, почему это не работает? Или что вы можете опубликовать буквальный пример того, как вы бы использовали его в этом случае?

2. Именно поэтому я написал свой комментарий к вашему вопросу. Если вы не используете необработанные строки ( r"b[a-z]b" ), b они будут интерпретироваться как символ пробела.

3. Оооооооооооо, вот что ты имел в виду :). Извините, сейчас 5: 30 утра, и я никогда не собирался устанавливать это соединение. Просто добавьте r, и это сработает великолепно! Спасибо, сэр.

4. В общем, это работает, но это приведет к сбою для слов со специальными символами (например, wenn bei Beförderungen Schäden )

5. @yekta: Нет, если вы компилируете регулярное выражение, используя опцию re.UNICODE или re.LOCALE . Я должен добавить это к своему ответу.

Ответ №2:

Знакомы ли вы с границами слов? ( b ). Вы можете извлекать слова, используя b вокруг последовательности и сопоставляя алфавит внутри:

 b([a-zA-Z] )b
  

Например, это захватит целые слова, но остановится на таких символах, как дефисы, точки, точки с запятой и т.д.

b Последовательность и другие можно найти в руководстве по python

РЕДАКТИРОВАТЬ Кроме того, если вы ищете число, следующее за совпадением или предшествующее ему, вы можете использовать отрицательный прогноз вперед / за:

 (?!d)   # negative look-ahead for numbers
(?<!d)  # negative look-behind for numbers
  

Комментарии:

1. Согласно ответу Тима, b звучит так, как я хочу, но это не очень приятно. Есть идеи? Я уже пробовал lookahead и lookbehinds, но они, похоже, соответствуют всем символам вплоть до символа, который находится рядом с числом, и поэтому не стоит полностью игнорировать слова с числами в них. Также он жалуется на то, что поисковикам нужны шаблоны фиксированной ширины с этими s там.

2. @Pie21: Тогда просто используйте однозначное совпадение. Нам все равно, сколько чисел после / предшествует ему, главное, чтобы там была цифра. <a rel="nofollow noreferrer noopener" href="https:///re.dabase.com/webre.py?input=pie21 21pie 21pie21 pieamp;regex=b(? пример

3. У меня получилось [re.findall (r» b([a-zA-Z] ) b», content, re.I) ] но, похоже, это не устраняет косые черты вперед и назад. Вот несколько слов, которые вышли: ‘[endif]’, ‘$’, ‘8’, ‘/ маленький’, ‘/li’

Ответ №3:

Как насчет:

 import re
yourString="pie 42 http://foo.com GIHQ4NWL0S5SCGBDD40ZXE5IDP13TYNEA  pie42"
filter (lambda x:re.match("^[a-zA-Z] $",x),[x for x in set(re.split("[s:/,.:]",yourString))])
  

Обратите внимание, что:

  • split разбивает вашу строку на потенциальных кандидатов => возвращает список «потенциальных слов»
  • set выполняет фильтрацию уникальности => преобразует список в set, таким образом удаляя записи, появляющиеся более одного раза. Этот шаг не является обязательным.
  • фильтр уменьшает количество кандидатов: берет список, применяет тестовую функцию к каждому элементу и возвращает список элемента, следующего за тестом. В нашем случае тестовая функция является «анонимной»
  • лямбда: анонимная функция, берущая элемент и проверяющая, является ли это словом (только заглавными или строчными буквами)

РЕДАКТИРОВАТЬ: добавлены некоторые пояснения

Комментарии:

1. Каким бы уродливым оно ни было, оно работает! Приветствия! Однако могу я попросить еще об одном одолжении: поскольку я не говорю на языке lambda ИЛИ filter, есть ли способ сделать что-то подобное с re.finditer() ? Мне также нужно отслеживать начальный и конечный индексы каждого совпадения в тексте.

Ответ №4:

Пример кода

 print re.search(ur'(?u)риветb', ur'Привет')
print re.search(ur'(?u)bриветb', ur'Привет')
  

или

 s = ur"abcd ААБВ"
import re
rx1 = re.compile(ur"(?u)АБВ")
rx2 = re.compile(ur"(?u)АБВb")
rx3 = re.compile(ur"(?u)bАБВb")
print rx1.findall(s)
print rx2.findall(s)
print rx3.findall(s)