Konversi antara Bentuk Normalisasi Unicode pada baris perintah unix

22

Dalam Unicode, beberapa kombinasi karakter memiliki lebih dari satu representasi.

Misalnya, karakter ä dapat direpresentasikan sebagai

  • "ä", itu adalah codepoint U + 00E4 (dua byte c3 a4dalam pengkodean UTF-8), atau sebagai
  • "ä", itu adalah dua codepoints U + 0061 U + 0308 (tiga byte 61 cc 88dalam UTF-8).

Menurut standar Unicode, dua representasi itu setara tetapi dalam "bentuk normalisasi" yang berbeda, lihat UAX # 15: Bentuk Normalisasi Unicode .

Kotak alat unix memiliki semua jenis alat transformasi teks, sed , tr , iconv , Perl datang ke pikiran. Bagaimana saya bisa melakukan konversi NF cepat dan mudah pada command-line?

glts
sumber
2
Sepertinya ada modul "Unicode :: Normalisasi" untuk perl yang harus melakukan hal seperti ini: search.cpan.org/~sadahiro/Unicode-Normalize-1.16/Normalize.pm
goldilocks
@goldilocks jika punya CLI ... Maksudku, aku lakukan perl -MUnicode::Normalization -e 'print NFC(... eh apa yang datang ke sini sekarang ...
mirabilos

Jawaban:

20

Anda dapat menggunakan uconvutilitas dari ICU . Normalisasi dicapai melalui transliterasi ( -x).

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

Pada Debian, Ubuntu dan turunan lainnya, uconvada dalam libicu-devpaket. Pada Fedora, Red Hat dan turunan lainnya, dan di port BSD, ada dalam icupaket.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
Ini berhasil, terima kasih. Anda harus menginstal perpustakaan dev 30M di sampingnya. Yang lebih buruk, saya belum dapat menemukan dokumentasi yang tepat untuk uconv sendiri: di mana Anda menemukan any-nfd? Sepertinya pengembangan alat ini telah ditinggalkan, pembaruan terakhir adalah pada tahun 2005.
glts
2
@ glts saya temukan any-nfddengan menelusuri daftar yang ditampilkan oleh uconv -L.
Gilles 'SO- stop being evil'
Di Ubuntu digunakan sudo apt install icu-devtoolsuntuk menjalankan uconv -x any-nfc, tetapi tidak memecahkan masalah yang paling sederhana , misalnya bugText.txt file dengan "Iglésias, Bad-á, Good-á" dikonversi oleh uconv -x any-nfc bugText.txt > goodText.txttetap teks yang sama.
Peter Krauss
7

Python memiliki unicodedatamodul di pustaka standarnya, yang memungkinkan untuk menerjemahkan representasi Unicode melalui unicodedata.normalize()fungsi:

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

Berjalan dengan Python 3.x:

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

Python tidak cocok untuk shell one liners, tetapi bisa dilakukan jika Anda tidak ingin membuat skrip eksternal:

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

Untuk Python 2.x Anda harus menambahkan line encoding ( # -*- coding: utf-8 -*-) dan menandai string sebagai Unicode dengan karakter u:

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

Periksa dengan hexdump alat:

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

00000000  61 cc 88                                          |a..|
00000003  

konversi dengan iconv dan periksa lagi dengan hexdump:

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

00000000  c3 a4                                             |..|
00000002

printf '\xc3\xa4'
ä
mtt2p
sumber
2
Ini hanya berfungsi pada macOS. Tidak ada 'utf-8-mac' di Linux, di FreeBSDs, dll. Juga, dekomposisi dengan menggunakan pengkodean ini tidak mengikuti spesifikasi (meskipun mengikuti algoritma normalisasi sistem file macOS). Info lebih lanjut: search.cpan.org/~tomita/Encode-UTF8Mac-0.04/lib/Encode/…
antonone
@antonone bersikap adil meskipun tidak ada OS yang ditentukan dalam pertanyaan.
roaima
1
@roaima Ya, itu sebabnya saya berasumsi bahwa jawabannya harus bekerja pada semua sistem yang didasarkan pada Unix / Linux. Jawaban di atas hanya berfungsi di macOS. Jika seseorang mencari jawaban khusus-makOS, maka sebagian akan berhasil. Saya hanya ingin menunjukkan hal itu, karena beberapa hari yang lalu saya kehilangan waktu bertanya-tanya mengapa saya tidak memiliki utf-8-macLinux dan apakah ini normal.
antonone
3

Untuk kelengkapan, dengan 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
sumber
2

coreutils memiliki patch untuk mendapatkan yang tepat unorm. bekerja dengan baik untuk saya pada 4byte wchars. mengikuti http://crashcourse.housegordon.org/coreutils-multibyte-support.html#unorm Masalah yang tersisa ada sistem wchar 2-byte (cygwin, windows, plus aix dan solaris pada 32bit), yang perlu mengubah codepoint dari atas pesawat menjadi pasangan pengganti dan sebaliknya, dan libunistring / gnulib yang mendasarinya belum bisa mengatasinya.

perl memiliki unicharsalat, yang juga melakukan berbagai bentuk normalisasi pada cmdline. http://search.cpan.org/dist/Unicode-Tussle/script/unichars

rurban
sumber