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.