Estoy tratando de eliminar algunos caracteres del archivo (UTF-8). Estoy usando tr
para este propósito:
tr -cs '[[:alpha:][:space:]]' ' ' <testdata.dat
El archivo contiene algunos caracteres extraños (como "Латвийская" o "àé"). tr
no parece entenderlos:los trata como no alfa y también los elimina.
Intenté cambiar algunas de mis configuraciones locales:
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
Desafortunadamente, ninguno de estos funcionó.
¿Cómo puedo hacer tr
entiende Unicode?
Respuesta aceptada:
Esa es una limitación conocida (1, 2, 3, 4, 5, 6) de la implementación GNU de tr
.
No es tanto que no sea compatible con extranjero , caracteres no ingleses o no ASCII, pero que no admite caracteres de varios bytes.
Esos caracteres cirílicos se tratarían bien, si estuvieran escritos en el juego de caracteres iso8859-5 (un byte por carácter) (y su configuración regional estaba usando ese juego de caracteres), pero su problema es que está usando UTF-8 donde no es ASCII los caracteres se codifican en 2 o más bytes.
GNU tiene un plan (ver también) para arreglar eso y el trabajo está en marcha pero aún no está listo.
FreeBSD o Solaris tr
no tienes el problema.
Mientras tanto, para la mayoría de los casos de uso de tr
, puede usar GNU sed o GNU awk que admiten caracteres de varios bytes.
Por ejemplo, su:
tr -cs '[[:alpha:][:space:]]' ' '
podría escribirse:
gsed -E 's/( |[^[:space:][:alpha:]])+/ /'
o:
gawk -v RS='( |[^[:space:][:alpha:]])+' '{printf "%s", sep $0; sep=" "}'
Para convertir entre minúsculas y mayúsculas (tr '[:upper:]' '[:lower:]'
):
gsed 's/[[:upper:]]/l&/g'
(que l
es una L
minúscula , no el 1
dígito).
o:
gawk '{print tolower($0)}'
Para portabilidad, perl
es otra alternativa:
perl -Mopen=locale -pe 's/([^[:space:][:alpha:]]| )+/ /g'
perl -Mopen=locale -pe '$_=lc$_'
Si sabe que los datos se pueden representar en un conjunto de caracteres de un solo byte, puede procesarlos en ese conjunto de caracteres:
(export LC_ALL=ru_RU.iso88595
iconv -f utf-8 |
tr -cs '[:alpha:][:space:]' ' ' |
iconv -t utf-8) < Russian-file.utf8