Saya membutuhkan utilitas internasional yang melakukan hal yang sama seperti tr
:mendapatkan karakter dari aliran dan menggantinya dengan karakter yang sesuai.
Bukan solusi kasus khusus seperti yang lebih rendah ke atas, tetapi solusi kasus umum diperlukan.
Tanpa gorillion piped sed
telepon jika memungkinkan.
Perhatikan bahwa tr
tidak bekerja di Linux:menerjemahkan byte, bukan karakter. Ini gagal dengan pengkodean multibyte.
$ tr --version | head -n 1
tr (GNU coreutils) 8.23
$ echo $LC_CTYPE
en_US.UTF-8
$ echo 'Ångstrom' | tr Æ Œ
Ņngstrom
Jawaban yang Diterima:
GNU sed
bekerja dengan karakter multi-byte. Jadi:
$ echo é½Æ | sed 'y/é½Æ/ABŒ/'
ABŒ
Bukannya GNU tr
belum diinternasionalkan tetapi tidak mendukung karakter multi-byte (seperti yang non-ASCII di lokal UTF-8). GNU tr
akan bekerja dengan Æ
, Œ
selama mereka byte tunggal seperti di set karakter iso8859-15.
Lebih lanjut tentang itu di Bagaimana membuat tr mengetahui karakter non-ascii(unicode)?
Bagaimanapun, itu tidak ada hubungannya dengan Linux, ini tentang tr
implementasi pada sistem. Apakah sistem itu menggunakan Linux sebagai kernel atau tr
dibuat untuk Linux atau menggunakan API kernel Linux tidak relevan karena bagian dari tr
fungsionalitas terjadi di ruang pengguna.
busybox tr
dan GNU tr
adalah yang paling umum ditemukan pada distribusi perangkat lunak yang dibuat untuk Linux dan tidak mendukung karakter multi-byte, tetapi ada yang lain yang telah di-porting ke Linux seperti tr
dari heirloom toolchest (porting dari OpenSolaris) atau ast-open yang melakukannya.
Perhatikan bahwa sed
y
tidak mendukung rentang seperti a-z
. Perhatikan juga bahwa jika skrip yang berisi sed 'y/é½Æ/ABŒ/'
ditulis dalam rangkaian karakter UTF-8, ia tidak akan berfungsi lagi seperti yang diharapkan jika dipanggil di lokal di mana UTF-8 bukan rangkaian karakter.
Alternatifnya bisa menggunakan perl
:
perl -Mopen=locale -Mutf8 -pe 'y/a-zé½Æ/A-ZABŒ/'
Di atas, kode perl diharapkan dalam UTF-8, tetapi akan memproses input dalam pengkodean lokal (dan output dalam pengkodean yang sama). Jika dipanggil dalam lokal UTF-8, itu akan mentransliterasi Æ
. UTF-8 (0xc3 0x86) ke Œ
U UTF-8 (0xc5 0x92) dan dalam ISO8859-15 sama tetapi untuk 0xc6 -> 0xbc.
Di sebagian besar shell, memiliki karakter UTF-8 di dalam tanda kutip tunggal harus OK bahkan jika skrip dipanggil di lokal di mana UTF-8 bukan charset (pengecualian adalah yash
yang akan mengeluh jika byte tersebut tidak membentuk karakter yang valid di lokal). Namun, jika Anda menggunakan kutipan selain kutipan tunggal, hal itu dapat menyebabkan masalah. Misalnya,
perl -Mopen=locale -Mutf8 -pe "y/♣`/&'/"
akan gagal di lokal di mana charset adalah BIG5-HKSCS karena penyandian Œ
(0x5c) kebetulan juga terdapat di beberapa karakter lain di sana (seperti α
:0xa3 0x5c, dan pengkodean UTF-8 dari ♣
kebetulan berakhir dengan 0xa3).
Bagaimanapun, jangan mengharapkan hal-hal seperti
perl -Mopen=locale -Mutf8 -pe 'y/Á-Ź/A-Z/'
untuk bekerja menghilangkan aksen akut. Di atas sebenarnya hanya
perl -Mopen=locale -Mutf8 -pe 'y/x{c1}-x{179}/x{41}-x{5a}/'
Artinya, rentang didasarkan pada titik kode unicode. Jadi rentang tidak akan berguna di luar urutan yang didefinisikan dengan sangat baik yang kebetulan berada di “kanan ” pesan dalam Unicode seperti A-Z
, 0-9
.
Jika Anda ingin menghilangkan aksen yang tajam, Anda harus menggunakan alat yang lebih canggih seperti:
perl -Mopen=locale -MUnicode::Normalize -pe '
$_ = NFKD($_); s/x{301}//g; $_ = NFKC($_)'
Yaitu menggunakan bentuk normalisasi Unicode untuk menguraikan karakter, menghilangkan aksen akut (di sini bentuk gabungan U+0301
) dan komposisi ulang.
Alat lain yang berguna untuk mentransliterasi Unicode adalah uconv
dari ICU. Misalnya, di atas juga dapat ditulis sebagai:
uconv -x '::NFKD; u0301>; ::NFKC;'
Padahal hanya akan bekerja pada data UTF-8. Anda membutuhkan:
iconv -t utf-8 | uconv -x '::NFKD; u0301>; ::NFKC;' | iconv -f utf-8
Untuk dapat memproses data di lokal pengguna.