Сообщить об ошибке.

Модуль unidecode в Python, unicode to ASCII

Представление Unicode в символах ASCII

Часто бывает так, что есть текстовые данные в Unicode, и их нужно представить в ASCII. Например, при интеграции с устаревшим кодом, который не поддерживает Unicode, или для упрощения ввода нелатинских имен на клавиатуре, или при создании машинных идентификаторов ASCII из удобочитаемых строк Unicode, которые должны быть несколько понятными. Популярным примером является создание URL-адресов из заголовка статьи.

Модуль unidecode не является заменой полной поддержки Unicode для строк. Есть ряд предостережений, связанных с его использованием, особенно когда его вывод непосредственно виден пользователям. Прежде чем использовать модуль unidecode в своем проекте, прочтите оставшуюся часть этого материала.

Примечание. Обратите внимание на модуль transliterate, который представляет собой двунаправленный транслитератор текста заточенный под славянские языки, такие как русский, сербский болгарский украинский и т.д.

Установка модуля unidecode в виртуальное окружение.

Модуль unidecode размещен на PyPI, поэтому установка относительно проста.

# создаем виртуальное окружение, если нет
$ python3 -m venv .venv --prompt VirtualEnv
# активируем виртуальное окружение 
$ source .venv/bin/activate
# обновляем `pip`
(VirtualEnv):~$ python3 -m pip install -U pip
# ставим модуль `unidecode`
(VirtualEnv):~$ python3 -m pip install -U unidecode

Содержание:


Основные моменты, связанные с unidecode.

Модуль unidecode принимает строки в Юникоде и пытается представить их в символах ASCII (т.е. универсально отображаемых символах между 0x00 и 0x7F), где компромиссы, принимаемые при сопоставлении между двумя наборами символов, выбираются так, чтобы они были близки к тому, что сделал бы человек на клавиатуре с раскладкой США.

Качество результирующего представления ASCII варьируется. Для языков западного происхождения оно должно быть между идеальным и хорошим. С другой стороны, транслитерация (т. е. передача латинскими буквами произношения, выраженного текстом в какой-либо другой системе письма) таких языков, как китайский, японский или корейский, является очень сложной проблемой, и этот модуль даже не пытается ее решить. Он придерживается линии контекстно-свободного посимвольного сопоставления. Таким образом, хорошее эмпирическое правило заключается в том, что чем дальше находится транслитерируемый язык от латинского алфавита, тем хуже будет транслитерация.

Как правило, модуль unidecode дает лучшие результаты, чем просто удаление акцентов из символов (что можно сделать в Python с помощью встроенных функций). Он основан на настроенных вручную сопоставлениях символов, которые, например, также содержат приближения ASCII для символов и нелатинских алфавитов.

Обратите внимание, что некоторые люди могут счесть определенные транслитерации оскорбительными. Наиболее распространенные примеры включают символы, которые используются в нескольких языках. Пользователь ожидает, что символ будет транслитерирован на его языке, но модуль unidecode использует транслитерацию для другого языка. Лучше не использовать этот модуль для строк, которые видны непосредственно пользователям приложения.

Функциональность модуля unidecode.

Модуль unidecode содержит функцию, которая принимает строковый объект, возможно, содержащий не-ASCII-символы, и возвращает строку, которую можно безопасно закодировать в ASCII:

>>> from unidecode import unidecode
>>> unidecode('Какой-то текст')
# 'Kakoi-to tekst'
>>> unidecode('Вячеслав, Юлия, Андрей, София')
'Viacheslav, Iuliia, Andrei, Sofiia'
>>> unidecode('kožušček')
# 'kozuscek'
>>> unidecode('30 \U0001d5c4\U0001d5c6/\U0001d5c1')
# '30 km/h'
>>> unidecode('\u5317\u4EB0')
# 'Bei Jing '

Также, для функции unidecode.unidecode() можно указать аргумент errors , который будет определять, что делать с символами, которых нет в таблицах транслитерации модуля. Значение по умолчанию - errors='ignore', что означает, что модуль unidecode будет игнорировать эти символы (заменит их пустой строкой). Значение errors='strict' вызовет ошибку UnidecodeError. Объект исключения будет содержать атрибут .index, который можно использовать для поиска символа-нарушителя. Значение errors='replace' заменит их на '?' (или другую строку, указанную в аргументе replace_str). Значение errors='preserve' сохранит исходный символ, отличный от ASCII, в строке.

Обратите внимание, что если используется 'preserve', то строка, возвращаемая unidecode.unidecode(), не будет кодироваться в ASCII!:

# unidecode не имеет замены для символов частной зоны
>>> unidecode('\ue000')
# ''
>>> unidecode('\ue000', errors='strict')
# Traceback (most recent call last):
# ...
# unidecode.UnidecodeError: no replacement found for character '\ue000' in position 0

Транслитерация текста из командной строки.

Модуль unidecode содержит CLI и утилиту, которые позволяют транслитерировать текст из командной строки несколькими способами.

Чтение со стандартного ввода:

$ echo 'какой-то текст' | unidecode
# kakoi-to tekst

Из параметра командной строки:

$ unidecode -c 'какой-то текст'
# kakoi-to tekst

Или из файла:

$ unidecode test.txt
# kakoi-to tekst

Кодировка по умолчанию, используемая утилитой, зависит от языкового стандарта используемой операционной системы. Можно указать другую кодировку с помощью параметра CLI -e.

Полный список доступных опций смотрите в выводе команды.

$ unidecode --help

Часто задаваемые вопросы.

  • Немецкие умлауты транслитерируются неправильно.

    Латинские буквы 'ä', 'ö' и 'ü' с диэрезисом транслитерируются Unidecode как 'a', 'o', 'u', а не в соответствии с немецкими правилами 'ae', 'oe', 'ue'. Это сделано намеренно и не будет меняться в дальнейшем. Обоснование заключается в том, что эти буквы используются на других языках, кроме немецкого (например, на финском и турецком). Текст на немецком языке, транслитерированный без дополнительной буквы “е”, гораздо более удобочитаем, чем текст на других языках, транслитерированный по немецким правилам. Обходной путь заключается в том, чтобы выполнить собственные замены этих символов перед передачей строки в функцию unidecode.unidecode().

    Пример функции замены:

    def de_to_ascii(text):
      chs = {'ß':'ss', 'ä':'ae', 'ö':'oe', 'ü':'ue'}
      for ch, val in chs.items():
          if ch in text:
              text = text.replace(ch, val)
      return text
    
  • Японский кандзи транслитерируется как китайский.

    Как и в случае с латинскими буквами с акцентами, обсуждаемыми в ответе выше, стандарт Unicode кодирует буквы, а не буквы определенного языка или их значение. С японским и китайским это еще более очевидно, потому что одна и та же буква может иметь очень разные транслитерации в зависимости от языка, в котором она используется. Так как модуль unidecode не выполняет транслитерацию для конкретного языка (см. следующий вопрос), он должен выбрать одну парадигму. Для некоторых символов, которые используются как в японском, так и в китайском языках, было принято решение использовать китайскую транслитерацию. Если необходимо транслитерировать японский, китайский или корейский текст, то рассмотрите возможность использования других модулей, которые выполняют транслитерацию для конкретного языка, например unihandecode.

  • Unidecode поддерживает локализацию? (например, параметр языка или страны, проверка локали системы и т. д.)

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

  • Unidecode автоматически определяет язык транслитерируемого текста?

    Определение языка - это совершенно отдельная проблема, выходящая за рамки этой библиотеки.

  • Почему Unidecode не заменяет символы обратной косой черты \u и \U в строках?

    Модуль unidecode ничего не знает об экранирующих последовательностях. Интерпретация этих последовательностей и замена их фактическими символами Юникода в строковых литералах является задачей интерпретатора Python.