tr: converte apóstrofo em ASCII


11

Estou tentando converter um aspas simples para um apóstrofo usando tr.

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

dado um arquivo codificado em UTF-8 chamado aque contém este exemplo:

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

O OS X usa o BSD tre produz um bom resultado:

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

O Ubuntu usa o GNU tre produz este resultado desagradável:

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

Como posso realizar essa conversão no Ubuntu?


Também tentei: tr $ '\ xE2 \ x80 \ x99' $ '\ x27' <a> b com os mesmos resultados.
Plamtrue


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

Respostas:


16

Você pode tentar outra ferramenta, como sed:

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

Ou, como estamos fazendo uma tradução simples, use o ycomando para sed:

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

O GNUtr não funciona presumivelmente porque:

Atualmente, trsuporta totalmente apenas caracteres de byte único. Eventualmente, ele suportará caracteres multibyte; quando isso acontecer, a -C opção fará com que complemente o conjunto de caracteres, enquanto -c fará com que complemente o conjunto de valores. Essa distinção será importante apenas quando alguns valores não forem caracteres, e isso só é possível em locais usando codificações multibyte quando a entrada contiver erros de codificação.

E é um caractere multibyte:

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

1
sedé muito melhor para esse tipo de trabalho.
Kaz Wolfe

2
Para explicar ainda mais a última parte: trestá substituindo cada um dos três bytes separadamente por ', portanto ''', assim como as seqüências quebradas em que ele substituiu dois dos três bytes nos caracteres semelhantes e . Em vez disso, deve entender os três bytes como juntos, significando um caractere e substituí-lo.
Deltab

Para melhor compreensão, é um caractere multibyte e também podemos usar o tr -c '[:print:][:cntrl:]' '-'comando para substituir todos os caracteres não imprimíveis , exceto os caracteres de controle válidos, por a -. E você verá uma tradução simples para 3 bytes de caracteres como ---. bom ponto para caracteres de vários bytes.
αғsнιη

9

Se você também deseja converter aspas duplas e talvez outros caracteres, use o GNUiconv :

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

O //TRANSLITsufixo informa iconvque, para caracteres fora do repertório da codificação de destino (aqui ASCII), ele pode substituir automaticamente caracteres ou seqüências de aparência semelhante. Sem o sufixo, iconvdesistirá assim que encontrar um caracter intraduzível.

Observe que //TRANSLITparece ser uma extensão do GNU: o POSIXiconv não suporta.


+1. Se você estiver convertendo um texto de um conjunto de caracteres (ou codificação) para outro, pode ser sensato usar uma ferramenta projetada para esse fim.
RedGrittyBrick

@deltab sua solução também substitui aspas duplas que o OP não deseja substituí-las.
αғsнιη

@KasiyA Talvez devessem.
Gerrit #

3

Você pode usar uma destas awksoluções:

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

Ou

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

0

Use a -sopção 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

1
sua solução também substitui aspas duplas que OP não querem substituí-los
αғsнιη

Ah, de fato, obrigado por apontar isso. Vou deixar esta resposta como referência.
Skippy le Grand Gourou
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.