Перетворення між формами нормалізації Unicode у командному рядку unix


22

У Unicode деякі комбінації символів мають більше одного представлення.

Наприклад, символ ä може бути представлений як

  • "ä", тобто кодова точка U + 00E4 (два байти c3 a4в кодуванні UTF-8), або як
  • "ä", тобто дві кодові точки U + 0061 U + 0308 (три байти 61 cc 88в UTF-8).

Згідно стандарту Unicode, два представлення є рівнозначними, але в різних "нормалізаційних формах", див. UAX № 15: Форми нормалізації Unicode .

У наборі інструментів unix є всілякі засоби перетворення тексту, sed , tr , iconv , Perl. Як я можу зробити швидке та просте перетворення NF у командному рядку?


2
Схоже, є модуль "Unicode :: нормалізація" для perl, який повинен робити такі речі: search.cpan.org/~sadahiro/Unicode-Normalize-1.16/Normalize.pm
goldilocks

@goldilocks, якщо у нього був CLI ... Я маю на увазі, я роблю perl -MUnicode::Normalization -e 'print NFC(... е, що зараз приходить сюди ...
mirabilos

Відповіді:


20

Ви можете скористатися uconvутилітою від ICU . Нормалізація досягається за допомогою транслітерації ( -x).

$ uconv -x any-nfd <<<ä | hd
00000000  61 cc 88 0a                                       |a...|
00000004
$ uconv -x any-nfc <<<ä | hd
00000000  c3 a4 0a                                          |...|
00000003

На Debian, Ubuntu та інші похідні uconvє в libicu-devпакеті. Для Fedora, Red Hat та інших похідних, а також для портів BSD - це icuпакет.


Це працює, дякую. Ви маєте встановити поряд із ним бібліотеку 30-мільйонних розробників. Що ще гірше, я не зміг знайти належну документацію для uconv: де ти знайшов any-nfd? Схоже, від розробки цього інструменту було відмовлено, останнє оновлення було у 2005 році.
glts

2
@glts Я знайшов any-nfd, переглядаючи список, показаний користувачем uconv -L.
Жил "ТАК - перестань бути злим"

У Ubuntu використовується sudo apt install icu-devtoolsдля запуску uconv -x any-nfc, але не для вирішення найпростішої проблеми , наприклад, bugText.txt файл із файлом "Iglésias, Bad-á, Good-á", перетворений за допомогою uconv -x any-nfc bugText.txt > goodText.txtтого самого тексту.
Пітер Краусс

7

unicodedataУ стандартній бібліотеці Python є модуль, який дозволяє переводити представлення Unicode через unicodedata.normalize()функцію:

import unicodedata

s1 = 'Spicy Jalape\u00f1o'
s2 = 'Spicy Jalapen\u0303o'

t1 = unicodedata.normalize('NFC', s1)
t2 = unicodedata.normalize('NFC', s2)
print(t1 == t2) 
print(ascii(t1)) 

t3 = unicodedata.normalize('NFD', s1)
t4 = unicodedata.normalize('NFD', s2)
print(t3 == t4)
print(ascii(t3))

Запуск з Python 3.x:

$ python3 test.py
True
'Spicy Jalape\xf1o'
True
'Spicy Jalapen\u0303o'

Python не дуже підходить для оболонок одного вкладиша, але це може бути зроблено, якщо ви не хочете створювати зовнішній скрипт:

$ python3 -c $'import unicodedata\nprint(unicodedata.normalize("NFC", "ääääää"))'
ääääää

Для Python 2.x вам потрібно додати рядок кодування ( # -*- coding: utf-8 -*-) та позначити рядки Unicode символом u:

$ python -c $'# -*- coding: utf-8 -*-\nimport unicodedata\nprint(unicodedata.normalize("NFC", u"ääääää"))'
ääääää

3

Перевірте це за допомогою інструмента hexdump:

echo  -e "ä\c" |hexdump -C 

00000000  61 cc 88                                          |a..|
00000003  

конвертувати з iconv і перевірити ще раз за допомогою hexdump:

echo -e "ä\c" | iconv -f UTF-8-MAC -t UTF-8 |hexdump -C

00000000  c3 a4                                             |..|
00000002

printf '\xc3\xa4'
ä

2
Це працює лише на macOS. У Linux, FreeBSD та ін. Немає «utf-8-mac». Також, декомпозиція за допомогою цього кодування не відповідає специфікаціям (вона все ж дотримується алгоритму нормалізації файлової системи macOS). Більше інформації: search.cpan.org/~tomita/Encode-UTF8Mac-0.04/lib/Encode/…
antonone

@antonone, щоб бути справедливим, хоча в питанні не було вказано ОС.
roaima

1
@roaima Так, тому я припустив, що відповідь має працювати у всіх системах, що базуються на Unix / Linux. Відповідь вище працює лише на macOS. Якщо хтось шукає відповідь, характерну для macOS, частково він буде працювати. Я просто хотів це зазначити, тому що днями я втратив деякий час, цікавившись, чому я не маю utf-8-macLinux та чи нормально це.
антонон

3

Для повноти perl:

$ perl -CSA -MUnicode::Normalize=NFD -e 'print NFD($_) for @ARGV' $'\ue1' | uconv -x name
\N{LATIN SMALL LETTER A}\N{COMBINING ACUTE ACCENT}
$ perl -CSA -MUnicode::Normalize=NFC -e 'print NFC($_) for @ARGV' $'a\u301' | uconv -x name
\N{LATIN SMALL LETTER A WITH ACUTE}

2

coreutils має патч для отримання належного unorm. добре працює для мене на 4-байтних wchars. слідкуйте за http://crashcourse.housegordon.org/coreutils-multibyte-support.html#unorm Залишилася проблема - 2-байтні системи wchar (cygwin, windows, плюс aix та solaris на 32bit), яким потрібно перетворити кодові точки з верхніх літаки в сурогатних парах і навпаки, і основні лібуністринг / гнуліб ще не впораються з цим.

perl має unicharsінструмент, який також робить різні форми нормалізації на cmdline. http://search.cpan.org/dist/Unicode-Tussle/script/unichars


2

Існує програма утиліти Perl, яка називається Charlint

https://www.w3.org/International/charlint/

що робить те, що ти хочеш. Вам також доведеться завантажити файл з

ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt

Після першого запуску Ви побачите, що Шарлінт скаржиться на несумісні записи у цьому файлі, тому вам доведеться видалити ці рядки з UnicodeData.txt.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.