Come rendere consapevoli i caratteri non ascii (unicode)?


36

Sto cercando di rimuovere alcuni caratteri dal file (UTF-8). Sto usando trper questo scopo:

tr -cs '[[:alpha:][:space:]]' ' ' <testdata.dat 

Il file contiene alcuni caratteri stranieri (come "Латвийская" o "àé"). trnon sembra capirli: li tratta come non alfa e li rimuove.

Ho provato a cambiare alcune delle mie impostazioni locali:

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

Sfortunatamente, nessuno di questi ha funzionato.

Come posso trcapire Unicode?

Risposte:


29

Questa è una limitazione nota ( 1 , 2 , 3 , 4 , 5 , 6 ) dell'implementazione GNU di tr.

Non è tanto che non supporta caratteri stranieri , non inglesi o non ASCII, ma che non supporta caratteri multibyte.

Quei caratteri cirillici sarebbero trattati OK, se scritti nel set di caratteri iso8859-5 (byte singolo per carattere) (e il tuo locale stava usando quel set di caratteri), ma il tuo problema è che stai usando UTF-8 dove non ASCII i caratteri sono codificati in 2 o più byte.

GNU ha un piano (vedi anche ) per risolverlo e il lavoro è in corso ma non è ancora arrivato .

FreeBSD o Solaris trnon hanno il problema.


Nel frattempo, per la maggior parte dei casi d'uso di tr, puoi usare GNU sed o GNU awk che supportano caratteri multi-byte.

Ad esempio, il tuo:

tr -cs '[[:alpha:][:space:]]' ' '

potrebbe essere scritto:

gsed -E 's/( |[^[:space:][:alpha:]])+/ /'

o:

gawk -v RS='( |[^[:space:][:alpha:]])+' '{printf "%s", sep $0; sep=" "}'

Per convertire tra lettere minuscole e maiuscole ( tr '[:upper:]' '[:lower:]'):

gsed 's/[[:upper:]]/\l&/g'

(questa lè una minuscola L, non la 1cifra).

o:

gawk '{print tolower($0)}'

Per la portabilità, perlè un'altra alternativa:

perl -Mopen=locale -pe 's/([^[:space:][:alpha:]]| )+/ /g'
perl -Mopen=locale -pe '$_=lc$_'

Se sai che i dati possono essere rappresentati in un set di caratteri a byte singolo, puoi elaborarli in quel set di caratteri:

(export LC_ALL=ru_RU.iso88595
 iconv -f utf-8 |
   tr -cs '[:alpha:][:space:]' ' ' |
   iconv -t utf-8) < Russian-file.utf8

1
Ho accettato la tua domanda a causa di informazioni su tr. Ho risolto il problema e rimosso la domanda su come risolverlo (quindi le persone che cercano tr troveranno solo informazioni su tr, non alcuni problemi arbitrari). Se potessi rimuovere anche la soluzione, poiché non è più necessaria, sarei grato.
Matthew Rock

3
@MatthewRock L'ho tenuto ma riformulato e reso più generico in quanto dare una parola in giro sarebbe utile per le persone con lo stesso problema.
Stéphane Chazelas,

Da dove viene l'idea che il cirillico sia (di solito) codificato in ISO 8859-5? Hai mai visto un testo russo in qualcosa di diverso da Unicode?
Incnis Mrsi,

9
@IncnisMrsi, tutto ciò che conta qui è che ISO 8859-5 è uno di quei caratteri a byte singolo con quei caratteri cirillici. Se è in uso diffuso o no è irrilevante qui. Se hai una localizzazione con KOI-R o il set di caratteri window-1251, invece, usala invece.
Stéphane Chazelas,

@IncnisMrsi Il russo sul web è quasi sempre codificato in UTF-8 (o occasionalmente in Windows-1251), ma solo perché abbiamo sentito il dolore di molte codifiche a byte singolo all'inizio. Ecco un'antica pagina web (circa 1998) con un commutatore di codifica (non funzionale): sch57.ru/collect .
Alex Shpilkin,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.