Converti tra i moduli di normalizzazione Unicode sulla riga comandi unix


22

In Unicode, alcune combinazioni di caratteri hanno più di una rappresentazione.

Ad esempio, il carattere ä può essere rappresentato come

  • "ä", ovvero il punto di codice U + 00E4 (due byte c3 a4nella codifica UTF-8) o come
  • "ä", ovvero i due punti di codice U + 0061 U + 0308 (tre byte 61 cc 88in UTF-8).

Secondo lo standard Unicode, le due rappresentazioni sono equivalenti ma in diverse "forme di normalizzazione", vedere UAX n. 15: Unicode Normalization Forms .

La toolbox unix ha tutti i tipi di strumenti di trasformazione del testo, come sed , tr , iconv , Perl. Come posso fare una conversione NF semplice e veloce dalla riga di comando?


2
Sembra che ci sia un modulo "Unicode :: Normalization" per perl che dovrebbe fare questo tipo di cose: search.cpan.org/~sadahiro/Unicode-Normalize-1.16/Normalize.pm
goldilocks

@goldilocks se avesse avuto un CLI ... Voglio dire, io perl -MUnicode::Normalization -e 'print NFC(... ehm, cosa viene qui adesso ...
mirabilos,

Risposte:


20

È possibile utilizzare l' uconvutilità da ICU . La normalizzazione si ottiene attraverso la traslitterazione ( -x).

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

Su Debian, Ubuntu e altri derivati, uconvè nel libicu-devpacchetto. Su Fedora, Red Hat e altri derivati ​​e nelle porte BSD, è nel icupacchetto.


Questo funziona, grazie. Tuttavia, devi installare una libreria di sviluppo 30M accanto ad essa. Quel che è peggio, non sono stato in grado di trovare la documentazione adeguata per uconv stesso: dove l'hai trovato any-nfd? Sembra che lo sviluppo di questo strumento sia stato abbandonato, l'ultimo aggiornamento è stato nel 2005.
inizia il

2
Ho trovato any-nfdsfogliando l'elenco visualizzato da uconv -L.
Gilles 'SO- smetti di essere malvagio' il

Su Ubuntu si utilizza sudo apt install icu-devtoolsper eseguire uconv -x any-nfc, ma non per risolvere il problema più semplice , ad esempio un bugText.txt file con "Iglésias, Bad-á, Good-á" convertito uconv -x any-nfc bugText.txt > goodText.txtmantenendo lo stesso testo.
Peter Krauss,

7

Python ha un unicodedatamodulo nella sua libreria standard, che consente di tradurre le rappresentazioni Unicode attraverso la unicodedata.normalize()funzione:

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

In esecuzione con Python 3.x:

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

Python non è adatto per i rivestimenti della shell one, ma può essere fatto se non si desidera creare script esterni:

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

Per Python 2.x devi aggiungere la riga di codifica ( # -*- coding: utf-8 -*-) e contrassegnare le stringhe come Unicode con il carattere u:

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

3

Controllalo con lo strumento hexdump:

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

00000000  61 cc 88                                          |a..|
00000003  

converti con iconv e ricontrolla con hexdump:

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

00000000  c3 a4                                             |..|
00000002

printf '\xc3\xa4'
ä

2
Funziona solo su macOS. Non c'è 'utf-8-mac' su Linux, su FreeBSD, ecc. Inoltre, la decomposizione usando questa codifica non segue le specifiche (ma segue l'algoritmo di normalizzazione del filesystem macOS). Maggiori informazioni: search.cpan.org/~tomita/Encode-UTF8Mac-0.04/lib/Encode/…
antonone

A dire il vero @antonone, sebbene nella domanda non sia stato specificato alcun sistema operativo.
roaima,

1
@roaima Sì, è per questo che ho pensato che la risposta dovrebbe funzionare su tutti i sistemi basati su Unix / Linux. La risposta sopra funziona solo su macOS. Se stai cercando una risposta specifica per macOS, funzionerà, in parte. Volevo solo evidenziarlo, perché l'altro giorno ho perso un po 'di tempo chiedendomi perché non ho utf-8-macsu Linux e se questo è normale.
antonone,

3

Per completezza, 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}

2

coreutils ha una patch per ottenere una corretta unorm. funziona bene per me su wchar 4byte. segui http://crashcourse.housegordon.org/coreutils-multibyte-support.html#unorm Il problema rimanente ci sono sistemi wchar a 2 byte (cygwin, windows, plus aix e solaris su 32bit), che devono trasformare i punti di codice dall'alto gli aerei in coppie surrogate e viceversa, e il sottostante libunistring / gnulib non può ancora gestirlo.

perl ha lo unicharsstrumento, che esegue anche le varie forme di normalizzazione sulla cmdline. http://search.cpan.org/dist/Unicode-Tussle/script/unichars


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.