J'essaie de supprimer certains caractères du fichier (UTF-8). J'utilise tr
à cet effet :
tr -cs '[[:alpha:][:space:]]' ' ' <testdata.dat
Le fichier contient des caractères étrangers (comme "Латвийская" ou "àé"). tr
ne semble pas les comprendre :il les traite comme non alpha et les supprime également.
J'ai essayé de modifier certains de mes paramètres régionaux :
LC_CTYPE=C LC_COLLATE=C tr -cs '[[:alpha:][:space:]]' ' ' <testdata.dat
LC_CTYPE=ru_RU.UTF-8 LC_COLLATE=C tr -cs '[[:alpha:][:space:]]' ' ' <testdata.dat
LC_CTYPE=ru_RU.UTF-8 LC_COLLATE=ru_RU.UTF-8 tr -cs '[[:alpha:][:space:]]' ' ' <testdata.dat
Malheureusement, rien de tout cela n'a fonctionné.
Comment puis-je faire tr
comprendre Unicode ?
Réponse acceptée :
C'est une limitation connue (1, 2, 3, 4, 5, 6) de l'implémentation GNU de tr
.
Ce n'est pas tant qu'il ne prend pas en charge foreign , des caractères non anglais ou non ASCII, mais qu'il ne prend pas en charge les caractères multi-octets.
Ces caractères cyrilliques seraient traités correctement, s'ils étaient écrits dans le jeu de caractères iso8859-5 (un seul octet par caractère) (et que vos paramètres régionaux utilisaient ce jeu de caractères), mais votre problème est que vous utilisez UTF-8 où non-ASCII les caractères sont encodés sur 2 octets ou plus.
GNU a un plan (voir aussi) pour résoudre ce problème et le travail est en cours mais pas encore là.
FreeBSD ou Solaris tr
n'ont pas le problème.
En attendant, pour la plupart des cas d'utilisation de tr
, vous pouvez utiliser GNU sed ou GNU awk qui prennent en charge les caractères multi-octets.
Par exemple, votre :
tr -cs '[[:alpha:][:space:]]' ' '
pourrait s'écrire :
gsed -E 's/( |[^[:space:][:alpha:]])+/ /'
ou :
gawk -v RS='( |[^[:space:][:alpha:]])+' '{printf "%s", sep $0; sep=" "}'
Pour convertir entre minuscules et majuscules (tr '[:upper:]' '[:lower:]'
):
gsed 's/[[:upper:]]/l&/g'
(que l
est un L
minuscule , pas le 1
chiffre).
ou :
gawk '{print tolower($0)}'
Pour la portabilité, perl
est une autre alternative :
perl -Mopen=locale -pe 's/([^[:space:][:alpha:]]| )+/ /g'
perl -Mopen=locale -pe '$_=lc$_'
Si vous savez que les données peuvent être représentées dans un jeu de caractères à un octet, vous pouvez les traiter dans ce jeu de caractères :
(export LC_ALL=ru_RU.iso88595
iconv -f utf-8 |
tr -cs '[:alpha:][:space:]' ' ' |
iconv -t utf-8) < Russian-file.utf8