tr: convierte el apóstrofe a ASCII

11

Estoy tratando de convertir una comilla simple a un apóstrofe usando tr.

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

dado un archivo codificado UTF-8 llamado aque contiene este ejemplo:

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

OS X usa el BSD try produce un buen resultado:

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

Ubuntu usa GNU try produce este desagradable resultado:

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

¿Cómo puedo lograr esta conversión en Ubuntu?

plamtrue
fuente
También probé: tr $ '\ xE2 \ x80 \ x99' $ '\ x27' <a> b con los mismos resultados.
plamtrue
1
Es bueno saber comillas ASCII y Unicode
αdesнιη
2
echo It’s easy | perl -CS -Mutf8 -pe "tr/’/'/"
tchrist

Respuestas:

16

Puedes probar alguna otra herramienta, como sed:

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

O, como estamos haciendo una traducción simple, use el ycomando para sed:

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

GNUtr no funciona presumiblemente porque:

Actualmente trsolo admite caracteres de un solo byte. Eventualmente admitirá caracteres multibyte; cuando lo haga, la -C opción hará que complemente el conjunto de caracteres, mientras que -c hará que complemente el conjunto de valores. Esta distinción solo importará cuando algunos valores no sean caracteres, y esto solo es posible en configuraciones regionales que usan codificaciones multibyte cuando la entrada contiene errores de codificación.

Y es un personaje multibyte:

$ echo -n \' | wc -c
1
$ echo -n  | wc -c  
3
muru
fuente
1
sedes mucho mejor para este tipo de trabajo.
Kaz Wolfe el
2
Para explicar más la última parte: trestá reemplazando cada uno de los tres bytes por separado con ', por '''lo tanto , así como las secuencias rotas donde ha reemplazado dos de los tres bytes en los caracteres similares y . En su lugar, debe comprender los tres bytes como si significaran un carácter, y reemplazarlos en su lugar.
deltab
Para entender bien, es un carácter multibyte, también podemos usar el tr -c '[:print:][:cntrl:]' '-'comando para reemplazar todos los caracteres que no se imprimen , que no sean caracteres de control válidos, con a -. Y verá una traducción única a 3 bytes de caracteres como ---. Buen punto para el carácter de varios bytes.
αғsнιη
9

Si también desea convertir las comillas dobles, y quizás otros caracteres, puede usar GNUiconv :

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

El //TRANSLITsufijo dice iconvque para caracteres fuera del repertorio de la codificación de destino (aquí ASCII), puede sustituir automáticamente caracteres o secuencias de aspecto similar. Sin el sufijo, se iconvrendirá tan pronto como encuentre un personaje intraducible.

Tenga en cuenta que //TRANSLITparece ser una extensión de GNU: POSIXiconv no lo admite.

deltab
fuente
+1. Si está convirtiendo un texto de un conjunto de caracteres (o codificación) a otro, puede ser sensato usar una herramienta diseñada para ese propósito.
RedGrittyBrick
@deltab su solución también reemplaza las comillas dobles que OP no quiere reemplazar.
αғsнιη
@KasiyA Quizás deberían hacerlo.
gerrit
3

Puede usar una de estas awksoluciones:

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
αғsнιη
fuente
0

-sOpción de uso de tr :

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

De man tr :

--truncate-set1
          first truncate SET1 to length of SET2
Skippy le Grand Gourou
fuente
1
su solución también reemplaza las comillas dobles que OP no quiere reemplazarlas
αғsнιη
Ah, de hecho, gracias por señalar esto. Dejaré esta respuesta como referencia.
Skippy le Grand Gourou