2 заметки с тегом

Unicode

Шпаргалка по формам/алгоритмам нормализации Unicode текста

Алгоритмы нормализации в Unicode нужны для преобразования внутренней структуры текста, чтобы потом с ним было проще работать. Например, можно заменить несколько символов одним, убрать все диакритические знаки из текста и даже преобразовать похожие буквы в их аналоги.

Всего есть четыре таких алгоритма: NFD, NFC, NFKD, NFKC. Каждый в отдельности можно запускать на одной и той же строке много раз, и результат от этого никак не изменится. То есть они идемпотентны.

Работать с Unicode текстом будем при помощи страндартной Python библиотеки unicodedata.

1. NFD (Normalization Form Canonical Decomposition) или форма нормализации D.

Раскладывает составные символы на несколько простых в соответствии с таблицами декомпозиции. Если хотя бы один из получившихся символов тоже составной, раскладываем и его до тех пор, пока не получим последовательность простых символов. То есть, алгоритм работает рекурсивно.

Получившаяся разложенная последовательность сортируется в некотором порядке, пока не очень понял в каком именно.

for c in unicodedata.normalize("NFD", "ё"):
    print("'%s': %s" % (c, unicodedata.name(c)))

>> 'е': CYRILLIC SMALL LETTER IE
>> '̈': COMBINING DIAERESIS

Так можно быстро подчистить всю диакритику в тексте, удаляя все ненужные группы символов из строки и оставляя только буквы.

2. NFC (Normalization Form Canonical Composition) или форма нормализации C.

Сначала выполняет NFD декомпозицию, а затем комбинирует полученные простые символы в составные. NFD декомпозиция тут нужна, чтобы разбить уже частично комбинированные символы на простые составляющие для последующей сортировки и обратной сборки.

for c in unicodedata.normalize("NFC", "ё"):
    print("'%s': %s" % (c, unicodedata.name(c)))

>> 'ё': CYRILLIC SMALL LETTER IO

Так можно быстро «приклеить» всю диакритику к буквам и получить из двух символов CYRILLIC SMALL LETTER IE и COMBINING DIAERESIS один CYRILLIC SMALL LETTER IO.

3. NFKD (Normalization Form Compatibility Decomposition) или форма нормализации KD.

Алгоритм, который выполняет NFD декомпозицию и заменяет похожие символы совместимыми аналогами, например, дробь ’¼’ заменяется на строку символов «1/4».

s = '⑲ ⁹ ¼'
print(unicodedata.normalize("NFKD", s))

>> 1 19 9 1/4

for c in list(s):
    print("'%s': %s - '%s'" % (c, unicodedata.name(c), unicodedata.normalize("NFKD", c)))

>> '⑲': CIRCLED NUMBER NINETEEN - '19'
>> ' ': SPACE - ' '
>> '⁹': SUPERSCRIPT NINE - '9'
>> ' ': SPACE - ' '
>> '¼': VULGAR FRACTION ONE QUARTER - '1⁄4'

После такой нормализации можно легко делать фильтрацию текста регэкспами, если его пытались усложнить и замаскировать от этого заменой похожих символов.

4. NFKC (Normalization Form Compatibility Composition) или форма нормализации KC.

Сначала выполняется совместимое разложение NFKD, а затем символы собираются вместе согласно NFC. Аналогично работе с NFC, можно быстро склеить всю диакритику с буквами, приведенными к некоторому базовому виду.

Проблемы NFKD и NFKC

При всем удобстве алгоритмов NFKD и NFKC, они не приводят некоторую часть визуально похожих символов к совместимым аналогам. Например, группу Negative Circled Number * из блока Enclosed Alphanumerics вполне можно привести к числам, но этого не происходит:

unicodedata.normalize("NFKC", "⓫ ⓯")

>> '⓫ ⓯'

А значит, если хочется сделать качественное приведение похожих символов, необходимое для многих задач, придется повозиться над своими таблицами замен.

 Нет комментариев    154   2020   Python   Unicode

mysqldump с учетом UTF-8

Если мы хотим сделать дамп базы MySQL и сохранить весь utf-8 набор символов, включая эмоджи и прочие радости жизни, то использовать такой классический пример будет очень плохой идеей:

mysqldump -u username -p database > db.dump

Так уже лучше, но эта команда сдампит только utf8, но не utf8mb4:

mysqldump -u username -p database -r db.dump

А вот так, будет совсем хорошо:

mysqldump -u username -p database --default-character-set=utf8mb4 --result-file=db.dump

Теперь, базу нужно импортировать на новое место.

Так — плохо:

mysql -u username -p database < db.dump

А вот так — хорошо:

$ mysql -u username -p --default-character-set=utf8mb4 database
mysql> SOURCE db.dump