tr: converte l'apostrofo in ASCII


11

Sto cercando di convertire le virgolette singole giuste in un apostrofo usando tr.

tr "`echo -e '\xE2\x80\x99'`" "`echo -e '\x27'`" < a > b

dato un file codificato UTF-8 chiamato ache contiene questo esempio:

Were not a different species
All alone?” Jeth mentioned.

OS X utilizza BSD tre produce un buon risultato:

We're not a different species
“All alone?” Jeth mentioned.

Ubuntu usa GNU tre produce questo brutto risultato:

We'''re not a different species
''<9C>All alone?''<9D> Jeth mentioned.

Come posso realizzare questa conversione in Ubuntu?


Anche provato: tr $ '\ xE2 \ x80 \ x99' $ '\ x27' <a> b con gli stessi risultati.
Plamtrue,

1

2
echo It’s easy | perl -CS -Mutf8 -pe "tr/’/'/"
tchrist,

Risposte:


16

Potresti provare qualche altro strumento, come sed:

$ sed "s/’/'/g" <a
We're not a different species
“All alone?” Jeth mentioned.

Oppure, poiché stiamo eseguendo una traduzione semplice, utilizzare il ycomando per sed:

$ sed "y/’/'/" <a
We're not a different species
“All alone?” Jeth mentioned.

GNUtr non funziona presumibilmente perché:

Attualmente trsupporta completamente solo caratteri a byte singolo. Alla fine supporterà i caratteri multibyte; in tal caso, l' -C opzione comporterà il completamento del set di caratteri, mentre -c comporterà il completamento del set di valori. Questa distinzione conta solo quando alcuni valori non sono caratteri, e ciò è possibile solo nelle versioni locali che utilizzano codifiche multibyte quando l'input contiene errori di codifica.

Ed è un personaggio multibyte:

$ echo -n \' | wc -c
1
$ echo -n  | wc -c  
3

1
sedè molto più bello per questo tipo di lavoro.
Kaz Wolfe,

2
Per spiegare ulteriormente l'ultima parte: trsta sostituendo ciascuno dei tre byte separatamente con ', quindi '''così come le sequenze interrotte in cui ha sostituito due dei tre byte con caratteri simili e . Dovrebbe invece comprendere i tre byte come insieme significando un carattere e sostituirlo invece.
deltab,

Per una buona comprensione è un carattere multibyte anche possiamo usare il tr -c '[:print:][:cntrl:]' '-'comando per sostituire ogni carattere non stampabile , diverso dai caratteri di controllo validi, con un -. E vedrai una singola traduzione in 3 byte di caratteri come ---. buon punto per il carattere multi-byte.
αғsнιη,

9

Se vuoi anche convertire le doppie virgolette e forse altri caratteri, puoi usare GNUiconv :

$ iconv -f utf-8 -t ascii//translit < a
We're not a different species
"All alone?" Jeth mentioned.

Il //TRANSLITsuffisso dice iconvche per i caratteri al di fuori del repertorio della codifica target (qui ASCII), può sostituire automaticamente caratteri o sequenze simili. Senza il suffisso, iconvsi arrenderà non appena troverà un carattere non traducibile.

Nota che //TRANSLITsembra essere un'estensione GNU: POSIXiconv non lo supporta.


+1. Se stai convertendo un testo da un set di caratteri (o codifica) a un altro, può essere sensato utilizzare uno strumento progettato a tale scopo.
RedGrittyBrick,

@deltab la tua soluzione sostituisce anche le doppie virgolette che OP non vuole sostituirle.
αғsнιη,

@KasiyA Forse dovrebbero.
Gerrit,

3

Puoi usare una di queste awksoluzioni:

awk '{gsub(/\xE2\x80\x99/, "\x27");print}' file # with Hex ASCII code

awk '{gsub(/’/, "\x27");print}' file

awk '{gsub(/\342\200\231/, "\47");print}'  file # with Octal ASCII code

awk '{gsub(/’/, "\47");print}' file

O

awk '{gsub(/’/, "'"'"'");print}' file

0

Utilizzare l' -sopzione di tr :

$ echo "We’re not a different species"|tr -s "’" "'"
We're not a different species

Da man tr :

--truncate-set1
          first truncate SET1 to length of SET2

1
la tua soluzione sostituisce anche le virgolette doppie che OP non vuole sostituirle
αғsнιη

Ah, davvero, grazie per averlo sottolineato. Lascio questa risposta come riferimento.
Skippy le Grand Gourou,
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.