Konwertuj między formularzami normalizacji Unicode w wierszu poleceń unix


22

W Unicode niektóre kombinacje znaków mają więcej niż jedną reprezentację.

Na przykład znak ä można przedstawić jako

  • „ä”, czyli punkt kodowy U + 00E4 (dwa bajty c3 a4w kodowaniu UTF-8) lub jako
  • „ä”, tj. dwa punkty kodowe U + 0061 U + 0308 (trzy bajty 61 cc 88w UTF-8).

Zgodnie ze standardem Unicode obie reprezentacje są równoważne, ale w różnych „formach normalizacji”, patrz UAX # 15: Formy normalizacji Unicode .

Przybornik unix ma wszystkie rodzaje narzędzi do przekształcania tekstu, sed , tr , iconv , Perl. Jak mogę szybko i łatwo przekonwertować NF w wierszu poleceń?


2
Wygląda na to, że jest to „Unicode :: Normalizacja” moduł Perl, który powinien zrobić tego rodzaju rzeczy: search.cpan.org/~sadahiro/Unicode-Normalize-1.16/Normalize.pm
Złotowłosa

@Goldilocks, jeśli miał CLI ... Mam na myśli, że perl -MUnicode::Normalization -e 'print NFC(... er, co teraz tu jest ...
mirabilos

Odpowiedzi:


20

Możesz użyć uconvnarzędzia z OIOM . Normalizację osiąga się poprzez transliterację ( -x).

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

Na Debianie, Ubuntu i innych pochodnych uconvjest w libicu-devpakiecie. W Fedorze, Red Hat i innych instrumentach pochodnych oraz w portach BSD jest w icupakiecie.


To działa, dzięki. Musisz jednak zainstalować obok niej bibliotekę programistów 30M. Co gorsza, nie byłem w stanie znaleźć odpowiedniej dokumentacji dla samego uconv: gdzie znalazłeś any-nfd? Wygląda na to, że prace nad tym narzędziem zostały porzucone, ostatnia aktualizacja miała miejsce w 2005 roku.
glt

2
@glts Znalazłem any-nfdprzeglądając listę wyświetlaną przez uconv -L.
Gilles „SO- przestań być zły”

Na Ubuntu używa się sudo apt install icu-devtoolsdo uruchomienia uconv -x any-nfc, ale nie rozwiązuje najprostszego problemu , np. bugText.txt Plik z „Iglésias, Bad-á, Good-á” przekonwertowany przez uconv -x any-nfc bugText.txt > goodText.txtpozostanie ten sam tekst.
Peter Krauss,

7

Python ma unicodedatamoduł w swojej standardowej bibliotece, który pozwala tłumaczyć reprezentacje Unicode poprzez unicodedata.normalize()funkcję:

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))

Działa z Python 3.x:

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

Python nie jest dobrze przystosowany do linerów powłoki 1, ale można to zrobić, jeśli nie chcesz tworzyć zewnętrznego skryptu:

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

W Pythonie 2.x musisz dodać kodowanie line ( # -*- coding: utf-8 -*-) i oznaczyć ciągi znaków jako Unicode znakiem u:

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

3

Sprawdź to za pomocą narzędzia hexdump:

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

00000000  61 cc 88                                          |a..|
00000003  

przekonwertuj za pomocą iconv i sprawdź ponownie za pomocą hexdump:

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

00000000  c3 a4                                             |..|
00000002

printf '\xc3\xa4'
ä

2
Działa to tylko w systemie macOS. W systemie Linux, FreeBSD nie ma „utf-8-mac” itp. Ponadto dekompozycja przy użyciu tego kodowania nie jest zgodna ze specyfikacją (ale algorytm normalizacji systemu plików macOS). Więcej informacji: search.cpan.org/~tomita/Encode-UTF8Mac-0.04/lib/Encode/…
antonone

@antonone, aby być uczciwym, chociaż nie określono systemu operacyjnego w pytaniu.
roaima

1
@roaima Tak, dlatego założyłem, że odpowiedź powinna działać na wszystkich systemach opartych na Unix / Linux. Powyższa odpowiedź działa tylko w systemie macOS. Jeśli szukasz odpowiedzi specyficznej dla systemu macOS, to częściowo zadziała. Chciałem tylko to podkreślić, ponieważ pewnego dnia straciłem trochę czasu, zastanawiając się, dlaczego nie mam utf-8-macLinuksa i czy to normalne.
antonone

3

Dla kompletności z 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 ma łatkę na poprawkę unorm. działa dobrze dla mnie na 4 bajtach wchars. śledź http://crashcourse.housegordon.org/coreutils-multibyte-support.html#unorm Pozostały problem to 2-bajtowe systemy wchar (cygwin, windows, aix i solaris na 32-bitowe), które muszą przekształcić punkty kodowe z górnej zamienia się w pary zastępcze i na odwrót, a leżące u podstaw libunistring / gnulib nie jest jeszcze w stanie tego obsłużyć.

perl ma unicharsnarzędzie, które wykonuje również różne formy normalizacji na cmdline. http://search.cpan.org/dist/Unicode-Tussle/script/unichars


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.