Converte entre Unicode Normalization Forms na linha de comando unix

22

No Unicode, algumas combinações de caracteres têm mais de uma representação.

Por exemplo, o caracter ä pode ser representado como

  • "ä", que é o ponto de código U + 00E4 (dois bytes c3 a4 na codificação UTF-8) ou como
  • "ä", ou seja, os dois pontos de código U + 0061 U + 0308 (três bytes 61 cc 88 em UTF-8).

De acordo com o padrão Unicode, as duas representações são equivalentes, mas em diferentes "formas de normalização", veja UAX # 15: Normalização Unicode Formulários .

A caixa de ferramentas unix tem todos os tipos de ferramentas de transformação de texto, sed , tr , iconv , Perl vem à mente. Como posso fazer uma conversão rápida e fácil da NF na linha de comando?

    
por glts 10.09.2013 / 20:47

6 respostas

18

Você pode usar o utilitário uconv de ICU . A normalização é alcançada através da transliteração ( -x ).

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

No Debian, Ubuntu e outros derivados, uconv está no pacote libicu-dev . No Fedora, Red Hat e outros derivados, e em portas BSD, está no pacote icu .

    
por 11.09.2013 / 03:51
7

O Python possui unicodedata module em sua biblioteca padrão, que permite traduzir representações Unicode através de unicodedata.normalize() function:

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

Correndo com o Python 3.x:

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

O Python não é adequado para o shell one liners, mas pode ser feito se você não quiser criar um script externo:

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

Para o Python 2.x, você precisa adicionar a linha de codificação ( # -*- coding: utf-8 -*- ) e marcar strings como Unicode com o caractere u:

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

Verifique com o hexdump da ferramenta:

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

00000000  61 cc 88                                          |a..|
00000003  

converta com iconv e verifique novamente com hexdump:

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

00000000  c3 a4                                             |..|
00000002

printf '\xc3\xa4'
ä
    
por 11.02.2017 / 15:39
2

o coreutils tem um patch para obter um unorm adequado. funciona bem para mim em 4 bytes wchars. siga link O problema restante são sistemas wchar de 2 bytes (cygwin, windows, mais aix e solaris em 32bits), que precisam transformar pontos de código de planos superiores em pares substitutos e vice-versa, e a libunistring / gnulib subjacente não pode lidar com isso ainda. / p>

perl tem a ferramenta unichars , que também faz as várias formas de normalização no cmdline. link

    
por 15.09.2017 / 09:32
2

Existe um utilitário perl chamado Charlint disponível em

link

que faz o que você quer. Você também terá que baixar um arquivo de

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

Após a primeira execução, você verá o Charlint reclamando sobre entradas incompatíveis nesse arquivo, então você terá que excluir essas linhas do UnicodeData.txt.

    
por 13.12.2017 / 11:34
1

Para completar, com 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}
    
por 15.09.2017 / 11:06