Pull to refresh

Очистка текста с помощью Python. Часть 1

Level of difficultyEasy
Reading time5 min
Views6.8K

Возьмем простейшую ситуацию, когда вы спарсили некоторые данные с Ф.И.О., номерами телефонов, email и именем пользователя с какого-либо сайта. Однако пользователи не особо любят соблюдать правила заполнения полей. Потому, иногда в Ф.И.О. присутствуют числа и различные символы, которые в дальнейшем затруднят поиск по таким данным. Да и номера телефонов могут быть записаны вразнобой. А потому, необходимо привести их к какому-то общему знаменателю. Следовательно, напрашивается логический вывод – данные необходимо очистить. Вот этим мы и займемся в данной статье.

Очистка текста с помощью Python. Часть 1 Python, IT, Программирование, Программист, Рекомендации, Разработка, Длиннопост

Я долгое время не обращал внимания на встроенные функции для фильтрации символов и пользовался простым «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)

Что же, думаю, что первая часть статьи на этом закончена. В следующей части статьи поговорим о том, как очистить цифры от букв и символов, а также нормализовать номер телефона. Напишем код для тестирования функций, которые мы написали для очистки текста и протестируем на примере.

А на этом, пожалуй, все.

Спасибо за внимание. Надеюсь, данная информация будет вам полезна

Подписывайся на наши телеграм каналы!

Tags:
Hubs:
Total votes 12: ↑4 and ↓80
Comments4

Articles