Convierta entre formularios de normalización Unicode en la línea de comandos de Unix

22

En Unicode, algunas combinaciones de caracteres tienen más de una representación.

Por ejemplo, el carácter ä puede representarse como

  • "ä", ese es el punto de código U + 00E4 (dos bytes c3 a4en la codificación UTF-8), o como
  • "ä", que son los dos puntos de código U + 0061 U + 0308 (tres bytes 61 cc 88en UTF-8).

De acuerdo con el estándar Unicode, las dos representaciones son equivalentes pero en diferentes "formas de normalización", vea UAX # 15: Formularios de normalización Unicode .

La caja de herramientas de Unix tiene todo tipo de herramientas de transformación de texto, sed , tr , iconv , Perl vienen a la mente. ¿Cómo puedo hacer una conversión NF rápida y fácil en la línea de comandos?

glts
fuente
2
Parece que hay un módulo de "Unicode :: normalización" para Perl que debe hacer este tipo de cosas: search.cpan.org/~sadahiro/Unicode-Normalize-1.16/Normalize.pm
GOLDILOCKS
@goldilocks si tuviera una CLI ... Quiero decir, sí perl -MUnicode::Normalization -e 'print NFC(... er lo que viene aquí ahora ...
mirabilos

Respuestas:

20

Puede usar la uconvutilidad desde la UCI . La normalización se logra a través de la transliteración ( -x).

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

En Debian, Ubuntu y otros derivados, uconvestá en el libicu-devpaquete. En Fedora, Red Hat y otros derivados, y en puertos BSD, está en el icupaquete.

Gilles 'SO- deja de ser malvado'
fuente
Esto funciona, gracias. Sin embargo, debes instalar una biblioteca de desarrollo de 30M. Lo que es peor, no he podido encontrar la documentación adecuada para uconv: ¿dónde la encontraste any-nfd? Parece que el desarrollo de esta herramienta ha sido abandonado, la última actualización fue en 2005.
glts
2
@glts que encontré any-nfdal navegar por la lista mostrada por uconv -L.
Gilles 'SO- deja de ser malvado'
En Ubuntu, sudo apt install icu-devtoolspara ejecutar uconv -x any-nfc, pero no resolver el problema más simple , por ejemplo, un bugText.txt archivo con "Iglésias, Bad-á, Good-á" convertido por uconv -x any-nfc bugText.txt > goodText.txtpermanecer el mismo texto.
Peter Krauss el
7

Python tiene un unicodedatamódulo en su biblioteca estándar, que permite traducir representaciones Unicode a través de la unicodedata.normalize()función:

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

Ejecutando con Python 3.x:

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

Python no es adecuado para los revestimientos de shell uno, pero se puede hacer si no desea crear un script externo:

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

Para Python 2.x, debe agregar la línea de codificación ( # -*- coding: utf-8 -*-) y marcar cadenas como Unicode con el carácter u:

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

Compruébelo con la herramienta hexdump:

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

00000000  61 cc 88                                          |a..|
00000003  

convierta con iconv y verifique nuevamente con hexdump:

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

00000000  c3 a4                                             |..|
00000002

printf '\xc3\xa4'
ä
mtt2p
fuente
2
Esto solo funciona en macOS. No hay 'utf-8-mac' en Linux, en FreeBSD, etc. Además, la descomposición mediante el uso de esta codificación no sigue la especificación (aunque sí sigue el algoritmo de normalización del sistema de archivos macOS). Más información: search.cpan.org/~tomita/Encode-UTF8Mac-0.04/lib/Encode/…
antonone
@antonone para ser justos, aunque no se especificó ningún sistema operativo en la pregunta.
roaima
1
@roaima Sí, por eso he asumido que la respuesta debería funcionar en todos los sistemas basados ​​en Unix / Linux. La respuesta anterior solo funciona en macOS. Si está buscando una respuesta específica de macOS, entonces funcionará, en parte. Solo quería señalar eso, porque el otro día perdí algo de tiempo preguntándome por qué no tengo utf-8-macLinux y si esto es normal.
antonone
3

Para completar, con 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}
Stéphane Chazelas
fuente
2

coreutils tiene un parche para obtener un apropiado unorm. funciona bien para mí en 4byte wchars. siga http://crashcourse.housegordon.org/coreutils-multibyte-support.html#unorm El problema restante son los sistemas wchar de 2 bytes (cygwin, windows, más aix y solaris en 32 bits), que necesitan transformar los puntos de código desde la parte superior planos en pares sustitutos y viceversa, y el libunistring / gnulib subyacente aún no puede manejar eso.

Perl tiene la unicharsherramienta, que también hace las diversas formas de normalización en la línea de cm. http://search.cpan.org/dist/Unicode-Tussle/script/unichars

rurban
fuente