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

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

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

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

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

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

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


person orlade    schedule 19.04.2011    source источник
comment
Лучше использовать необработанные строки с регулярными выражениями. \d работает, но другие escape-последовательности не работают, и это может быть сложно отладить.   -  person Tim Pietzcker    schedule 19.04.2011


Ответы (4)


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

\b[a-z]+\b

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

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

\b[^\W\d_]+\b

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

[^\W\d_] как класс символов с отрицательным знаком допускает использование любых буквенно-цифровых символов, кроме цифр и символа подчеркивания.

person Tim Pietzcker    schedule 19.04.2011
comment
Это звучит именно так, как я хочу, но я не могу заставить работать \b. Если text установлено как обычное предложение, re.findall('\b[a-z]+\b', text, re.I) ничего не возвращает. Независимо от того, что я помещал в квадратные скобки (или использовал search или match), похоже, это тоже не помогает. Использование \B дает мне некоторые результаты, но удаляет первый и последний символ каждого слова. Как бы лениво это ни звучало, я слишком устал, чтобы прямо сейчас подобрать новую концепцию; есть ли шанс, что вы знаете, почему это не работает? Или что вы можете опубликовать буквальный пример того, как вы будете использовать его в этом случае? - person orlade; 19.04.2011
comment
именно поэтому я написал свой комментарий к вашему вопросу. Если вы не используете необработанные строки (r"\b[a-z]\b"), \b будет интерпретироваться как символ возврата. - person Tim Pietzcker; 19.04.2011
comment
Ооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооо это то, что вы имели в виду :). Извините, сейчас 5:30 утра, и я никогда не собирался устанавливать эту связь. Просто добавьте r, и все получится! Спасибо, сэр. - person orlade; 19.04.2011
comment
В целом это работает, но не работает со словами со специальными символами (например, wenn bei Beförderungen Schäden). - person yekta; 25.06.2017
comment
@yekta: Нет, если вы скомпилируете регулярное выражение с параметром re.UNICODE или re.LOCALE. Я должен добавить это к своему ответу. - person Tim Pietzcker; 25.06.2017

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

\b([a-zA-Z]+)\b

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

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

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

(?!\d)   # negative look-ahead for numbers
(?<!\d)  # negative look-behind for numbers
person Brad Christie    schedule 19.04.2011
comment
Согласно ответу Тима, \b звучит как то, что я хочу, но это не очень хорошо. Любые идеи? Раньше я пробовал смотреть вперед и смотреть назад, но они, кажется, соответствуют всем символам вплоть до символа, который примыкает к числу, и поэтому не полностью игнорируют слова с числами в них. Также он жалуется на то, что для просмотра вперед нужны шаблоны фиксированной ширины с этими + там. - person orlade; 19.04.2011
comment
@ Pie21: Тогда просто используйте совпадение из одной цифры. Нас не волнует, сколько цифр следует/предшествует этому, просто есть цифра. пример - person Brad Christie; 19.04.2011
comment
У меня это работает [ re.findall(r\b([a-zA-Z]+)\b,content, re.I) ], но, похоже, оно не отсеивает прямую и обратную косую черту. Вот некоторые слова, которые вышли: '[endif]', '$', '8', '/small', '/li' - person Bill; 09.07.2015

Что о:

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, таким образом удаляя записи, появляющиеся более одного раза. Этот шаг не является обязательным.
  • filter уменьшает количество кандидатов: берет список, применяет тестовую функцию к каждому элементу и возвращает список элементов, прошедших проверку. В нашем случае тестовая функция "анонимная".
  • lambda : анонимная функция, берущая элемент и проверяющая, является ли это словом (только заглавные или строчные буквы)

EDIT: добавлено несколько пояснений

person Bruce    schedule 19.04.2011
comment
Уродливо, как это, это работает! Ваше здоровье! Однако могу я попросить еще об одной услуге: поскольку я не говорю о лямбда-фильтре ИЛИ, есть ли способ сделать что-то подобное с re.finditer()? Мне также нужно отслеживать начальный и конечный индексы каждого совпадения в тексте. - person orlade; 19.04.2011

Образец кода

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

or

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)
person Alexander Lubyagin    schedule 06.12.2017