#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)