Очистка текста с помощью Python. Часть 1
Возьмем простейшую ситуацию, когда вы спарсили некоторые данные с Ф.И. О., номерами телефонов, email и именем пользователя с какого-либо сайта. Однако пользователи не особо любят соблюдать правила заполнения полей. Потому, иногда в Ф.И. О. присутствуют числа и различные символы, которые в дальнейшем затруднят поиск по таким данным. Да и номера телефонов могут быть записаны вразнобой. А потому, необходимо привести их к какому-то общему знаменателю. Следовательно, напрашивается логический вывод — данные необходимо очистить. Вот этим мы и займемся в данной статье.
Я долгое время не обращал внимания на встроенные функции для фильтрации символов и пользовался простым «replace». Однако, при таком методе всех символов, которые необходимо заменить, учесть просто невозможно, так как их может быть не одна сотня. Тем не менее, в python уже есть встроенное средство, которое позволит нам оставить только буквы, убрав все остальные символы — isalpha (). Он возвращает True, если символ является алфавитным. Если же нет, возвращается False. Также, с помощью метода isdecimal () можно убрать все буквы и символы, кроме цифр. Ну, а если наличие цифр и букв критично, а вот символы желательно убрать, можно воспользоваться методом isalnum ().
Очистка строк от символов и цифр
Давайте же перейдем от слов к делу и напишем небольшую функцию, которая будет производить необходимые операции. Предположим, что у нас есть строка с Ф.И. О., которую необходимо очистить. Возьмем что-то вымышленное и добавим в него цифры и символы.
Например: Дьяченко-Волобуев))#90= Олег владиmирович52415
Как видим, здесь всего хватает. Это не предел. Встречается еще и похуже. Итак, начнем с того, что создадим функцию fio_normalize (fio: str, ascii_l: bool) → str, которая будет принимать на вход текст, и возвращать его в очищенном виде.
Иногда вместо Ф.И. О. встречаются строки, которые содержат спам. То есть, в них содержится ссылка. Потому, для начала проверим, есть ли «http» в строке. Если есть, чистить дальше не имеет смысла и нужно просто возвратить пустое значение.
if «http» in fio or «https» in fio or «Http» in fio or «Https» in fio:
return »
Также, в строке может содержаться тире. Ведь фамилия может быть составной, что-то вроде: Петров-Водкин. Потому, нужно проверить, есть ли тире в строке. Если в начале и конце, удалить. Затем проверить, есть ли в самой строке и если есть, заменить на слово. Это нужно для того, чтобы не удалить символ методом isalpha ().
if fio.startswith("-") or fio.endswith("-"):
fio = fio.strip("-").strip()
if "-" in fio:
fio = fio.replace("-", "тирре")
Теперь, собственно, строка подготовлена для удаления символов и цифр. Поэтому, выполняем данную операцию и заменяем слово, на которое мы заменили »-».
fio = "".join(x for x in fio if x.isalpha() or x == " ").strip().replace("тирре", "-")
Еще, в строке может присутствовать транслитерация. Это когда русские буквы заменены на английские. Например: Petrov. В данном случае может помочь библиотека «transliterate». Однако, сильно надеяться на нее не стоит, так как разные люди пишут разные окончания по разному. И потому, слово может быть просто искажено. Слегка. И для человека не существенно. Но вот для поиска уже проблема. Тем не менее, попытаться выполнить транслитерацию стоит. Ведь может и повезти. Потому устанавливаем модуль «transliterate» с помощью команды в терминале:
pip install transliterate
и импортируем в наш скрипт:
from transliterate import translit
Однако, прежде чем проводить транслитерацию, следует понять, является ли слово из английских букв. Для этого мы будем использовать счетчик и библиотеку string, а точнее ее метод ascii_letters. После чего сравним полученное число в количеством символов в строке. И если оно совпадает, значит данное слово нуждается в транслитерации.
Однако, это еще не все. Иногда попадается такая веселая штука, когда на первый взгляд строка написана по-русски. Но, когда приглядишься, понимаешь, что некоторые символы в ней заменены на английский буквы. Вот их тоже надо вычистить. Например: «н» может быть заменено на «h».
Для этого нужно составить таблицу замены и производить ее с помощью дополнительной функции, которую нужно написать. Однако, о ней чуть позже. А пока, примем за факт, что функция есть, и с помощью ее мы делаем замену букв в словах.
if ascii_l and ascii_count == len(fio):
fio = translit(fio, "ru")
elif ascii_l:
temp = []
for x in fio:
temp.append(replacer(x)) if x in string.ascii_letters else temp.append(x)
fio = "".join(temp)
Следующее, что нужно сделать, это написать каждое слово в Ф.И. О. с заглавной буквы. А также учесть наличие тире в составной фамилии. Потому, напишем еще небольшой кусочек кода.
fio = " ".join(x.strip().capitalize() for x in fio.split())
lst = []
for x in fio.split():
if "-" in x:
lst.append("-".join(z.capitalize() for z in x.split("-")))
else:
lst.append(x)
fio = " ".join(lst)
Так как у нас Ф.И. О., то оно должно содержать только три слова. Сейчас не берем в расчет не совсем традиционные написания. Поэтому нужно сделать проверку на количество слов в строке. И если их больше трех, обрезать до нужного количества.
Еще нужно проверить, чтобы строка была не длиннее 50 символов. Конечно для Ф.И. О. это редкость. Но бывает и такое. Потому, оставляем его для заполненности, но обрежем до 50 символов. Почему? Дело в том, что если вы добавляете данные в БД SQLite, то это не имеет значения. А вот уже при добавлении в MongoDB и последующее создание индексов, мы получим ошибку на количество символов в индексируемом поле.
if len(fio.split()) > 3:
fio = " ".join(fio.split()[0:3])
if len(fio) > 50:
fio = fio[:51]
Ну и возвращаем обработанную строку из функции. Или пустоту, если строка пуста.
return fio if fio else ""
Полный код функции очистки строки
def fio_normalize(fio: str, ascii_l=True) -> str:
if "http" in fio or "https" in fio or "Http" in fio or "Https" in fio:
return ""
if fio.startswith("-") or fio.endswith("-"):
fio = fio.strip("-").strip()
if "-" in fio:
fio = fio.replace("-", "тирре")
fio = "".join(x for x in fio if x.isalpha() or x == " ").strip().replace("тирре", "-")
ascii_count = 0
for xz in fio:
if xz == " ":
ascii_count += 1
ascii_count += sum(1 for x in xz if x in string.ascii_letters)
if ascii_l and ascii_count == len(fio):
fio = translit(fio, "ru")
elif ascii_l:
temp = []
for x in fio:
temp.append(replacer(x)) if x in string.ascii_letters else temp.append(x)
fio = "".join(temp)
fio = " ".join(x.strip().capitalize() for x in fio.split())
lst = []
for x in fio.split():
if "-" in x:
lst.append("-".join(z.capitalize() for z in x.split("-")))
else:
lst.append(x)
fio = " ".join(lst)
if len(fio.split()) > 3:
fio = " ".join(fio.split()[0:3])
if len(fio) > 50:
fio = fio[:51]
return fio if fio else ""
Теперь нужно еще поговорить о функции, с помощью которой мы будем заменять те самые вхождения английских букв в русские слова. Создадим функцию def replacer (txt: str) → str, которая на вход получаем символ и возвращает уже замененный, если он есть в таблице замены.
def replacer(txt: str) -> str:
symbols = ("ahkbtmxcepAHKBTMXCEP",
"анквтмхсерАНКВТМХСЕР")
tr = {ord(a): ord(b) for a, b in zip(*symbols)}
return txt.translate(tr)
Что же, думаю, что первая часть статьи на этом закончена. В следующей части статьи поговорим о том, как очистить цифры от букв и символов, а также нормализовать номер телефона. Напишем код для тестирования функций, которые мы написали для очистки текста и протестируем на примере.
А на этом, пожалуй, все.
Спасибо за внимание. Надеюсь, данная информация будет вам полезна
Подписывайся на наши телеграм каналы!