Ho bisogno di un'utilità internazionalizzata che faccia la stessa cosa di tr
:ottiene il carattere dallo stream e lo sostituisce con un carattere corrispondente.
Non è necessaria una soluzione per casi particolari come dal basso verso l'alto, ma è necessaria una soluzione per casi generali.
Senza gorillion piped sed
chiama se possibile.
Nota che tr
non funziona su Linux:traduce byte, non caratteri. Questo non riesce con le codifiche multibyte.
$ tr --version | head -n 1
tr (GNU coreutils) 8.23
$ echo $LC_CTYPE
en_US.UTF-8
$ echo 'Ångstrom' | tr Æ Œ
Ņngstrom
Risposta accettata:
GNU sed
funziona con caratteri multibyte. Quindi:
$ echo é½Æ | sed 'y/é½Æ/ABŒ/'
ABŒ
Non è tanto GNU tr
non è stato internazionalizzato ma non supporta i caratteri multibyte (come quelli non ASCII nelle localizzazioni UTF-8). GNU tr
funzionerebbe con Æ
, Œ
purché fossero a byte singolo come nel set di caratteri iso8859-15.
Maggiori informazioni su Come rendere tr consapevole dei caratteri non ascii(unicode)?
In ogni caso, questo non ha nulla a che fare con Linux, si tratta di tr
implementazione sul sistema. Se quel sistema usa Linux come kernel o tr
è costruito per Linux o usa l'API del kernel Linux non è rilevante in quanto quella parte di tr
la funzionalità avviene nello spazio utente.
occupatobox tr
e GNU tr
sono i più comuni nelle distribuzioni di software creati per Linux e non supportano i caratteri multibyte, ma ce ne sono altri che sono stati portati su Linux come tr
della cassetta degli attrezzi cimelio (portato da OpenSolaris) o di ast-open che lo fanno.
Nota che sed
's y
non supporta intervalli come a-z
. Nota anche che se quello script che contiene sed 'y/é½Æ/ABŒ/'
è scritto nel set di caratteri UTF-8, non funzionerà più come previsto se chiamato in una locale in cui UTF-8 non è il set di caratteri.
Un'alternativa potrebbe essere usare perl
:
perl -Mopen=locale -Mutf8 -pe 'y/a-zé½Æ/A-ZABŒ/'
Sopra, il codice perl dovrebbe essere in UTF-8, ma elaborerà l'input nella codifica della locale (e l'output nella stessa codifica). Se chiamato in una locale UTF-8, traslittererà un UTF-8 Æ
(0xc3 0x86) a un Œ
UTF-8 (0xc5 0x92) e in un ISO8859-15 stesso ma per 0xc6 -> 0xbc.
Nella maggior parte delle shell, avere quei caratteri UTF-8 tra virgolette singole dovrebbe essere OK anche se lo script viene chiamato in una locale in cui UTF-8 non è il set di caratteri (un'eccezione è yash
che si lamenterebbe se quei byte non formano caratteri validi nella locale). Tuttavia, se stai utilizzando virgolette diverse dalle virgolette singole, potrebbero causare problemi. Ad esempio,
perl -Mopen=locale -Mutf8 -pe "y/♣`/&'/"
fallirebbe in una locale in cui il set di caratteri è BIG5-HKSCS perché la codifica di (0x5c) è contenuto anche in altri caratteri (come
α
:0xa3 0x5c e la codifica UTF-8 di ♣
finisce con 0xa3).
In ogni caso, non aspettarti cose come
perl -Mopen=locale -Mutf8 -pe 'y/Á-Ź/A-Z/'
lavorare per rimuovere gli accenti acuti. Quanto sopra è in realtà solo
perl -Mopen=locale -Mutf8 -pe 'y/x{c1}-x{179}/x{41}-x{5a}/'
Cioè, l'intervallo si basa sui punti di codice unicode. Quindi gli intervalli non saranno utili al di fuori di sequenze molto ben definite che si trovano nella "destra ” ordina in Unicode come A-Z
, 0-9
.
Se vuoi rimuovere gli accenti acuti, dovresti utilizzare strumenti più avanzati come:
perl -Mopen=locale -MUnicode::Normalize -pe '
$_ = NFKD($_); s/x{301}//g; $_ = NFKC($_)'
Cioè usa i moduli di normalizzazione Unicode per scomporre i caratteri, rimuovere gli accenti acuti (qui il modulo di combinazione U+0301
) e ricomporre.
Un altro strumento utile per traslitterare Unicode è uconv
dalla terapia intensiva. Ad esempio, quanto sopra potrebbe anche essere scritto come:
uconv -x '::NFKD; u0301>; ::NFKC;'
Anche se funzionerebbe solo su dati UTF-8. Avresti bisogno di:
iconv -t utf-8 | uconv -x '::NFKD; u0301>; ::NFKC;' | iconv -f utf-8
Per poter elaborare i dati nella locale dell'utente.