Potřebuji internacionalizovaný nástroj, který dělá to samé jako tr
:získá znak ze streamu a nahradí jej odpovídajícím znakem.
Nejedná se o řešení konkrétního případu jako od nižšího k hornímu, ale je potřeba obecné řešení případu.
Bez gorillion piped sed volání, pokud je to možné.
Všimněte si, že tr
nefunguje na Linuxu:překládá bajty, nikoli znaky. Toto selhává u vícebajtových kódování.
$ tr --version | head -n 1
tr (GNU coreutils) 8.23
$ echo $LC_CTYPE
en_US.UTF-8
$ echo 'Ångstrom' | tr Æ Œ
Ņngstrom
Přijatá odpověď:
GNU sed
pracuje s vícebajtovými znaky. Takže:
$ echo 齯 | sed 'y/齯/ABŒ/'
ABŒ
Není to tak moc, že GNU tr
nebyl internacionalizován, ale že nepodporuje vícebajtové znaky (jako ty bez ASCII v národních prostředích UTF-8). GNU tr
bude fungovat s Æ
, Œ
pokud byly jednobajtové jako ve znakové sadě iso8859-15.
Více o tom na Jak upozornit na ne-ascii (unicode) znaky?
V každém případě to nemá nic společného s Linuxem, je to o tr
implementace v systému. Zda tento systém používá Linux jako jádro nebo tr
je vytvořen pro Linux nebo používá linuxové jádro API není relevantní, protože tato část tr
funkčnost se odehrává v uživatelském prostoru.
busybox tr
a GNU tr
se nejčastěji vyskytují v distribucích softwaru vytvořeného pro Linux a nepodporují vícebajtové znaky, ale existují i jiné, které byly portovány na Linux, jako je tr
z heirloom toolchest (portováno z OpenSolaris) nebo z ast-open, které to dělají.
Všimněte si, že sed
's y
nepodporuje rozsahy jako a-z
. Všimněte si také, že pokud tento skript obsahuje sed 'y/齯/ABŒ/'
je zapsán ve znakové sadě UTF-8, nebude již fungovat podle očekávání, pokud bude volán v národním prostředí, kde UTF-8 není znaková sada.
Alternativou může být použití perl
:
perl -Mopen=locale -Mutf8 -pe 'y/a-z齯/A-ZABŒ/'
Výše se očekává, že kód perl bude v UTF-8, ale zpracuje vstup v kódování národního prostředí (a výstup ve stejném kódování). Pokud je voláno v národním prostředí UTF-8, přepíše UTF-8 Æ
(0xc3 0x86) na UTF-8 Œ
(0xc5 0x92) a v ISO8859-15 stejné, ale pro 0xc6 -> 0xbc.
Ve většině shellů by mělo být umístění těchto znaků UTF-8 v jednoduchých uvozovkách v pořádku, i když je skript volán v národním prostředí, kde UTF-8 není znaková sada (výjimkou je yash
což by si stěžovalo, pokud tyto bajty netvoří platné znaky v národním prostředí). Pokud však používáte jiné než jednoduché uvozovky, může to způsobit problémy. Například,
perl -Mopen=locale -Mutf8 -pe "y/♣`/&'/"
by selhal v národním prostředí, kde je znaková sada BIG5-HKSCS, protože kódování (0x5c) je shodou okolností obsaženo i v některých dalších znacích (například
α
:0xa3 0x5c a kódování UTF-8 ♣
náhodou končí 0xa3).
V žádném případě nečekejte věci jako
perl -Mopen=locale -Mutf8 -pe 'y/Á-Ź/A-Z/'
pracovat na odstranění akutních akcentů. Výše uvedené je vlastně jen
perl -Mopen=locale -Mutf8 -pe 'y/x{c1}-x{179}/x{41}-x{5a}/'
To znamená, že rozsah je založen na kódových bodech unicode. Rozsahy tedy nebudou užitečné mimo velmi dobře definované sekvence, které jsou náhodou „správně ” pořadí v Unicode jako A-Z
, 0-9
.
Pokud chcete odstranit ostré akcenty, budete muset použít pokročilejší nástroje, jako je:
perl -Mopen=locale -MUnicode::Normalize -pe '
$_ = NFKD($_); s/x{301}//g; $_ = NFKC($_)'
To znamená použití normalizačních formulářů Unicode k rozložení znaků, odstranění ostrých akcentů (zde kombinační formulář U+0301
) a znovu složte.
Dalším užitečným nástrojem pro přepis Unicode je uconv
z JIP. Výše uvedené může být například také zapsáno jako:
uconv -x '::NFKD; u0301>; ::NFKC;'
I když by fungoval pouze na datech UTF-8. Budete potřebovat:
iconv -t utf-8 | uconv -x '::NFKD; u0301>; ::NFKC;' | iconv -f utf-8
Aby bylo možné zpracovávat data v národním prostředí uživatele.