tr: przekonwertuj apostrof na ASCII

11

Próbuję przekonwertować pojedynczy pojedynczy cudzysłów na apostrof za pomocą tr.

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

podany plik o nazwie UTF-8 o nazwie, aktóry zawiera ten przykład:

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

OS X używa BSD tri daje niezły wynik:

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

Ubuntu używa GNU tri daje ten paskudny wynik:

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

Jak mogę dokonać tej konwersji w Ubuntu?

plamtrue
źródło
Próbowałem także: tr $ '\ xE2 \ x80 \ x99' $ '\ x27' <a> b z tymi samymi wynikami.
plamtrue
1
Dobrze jest znać znaki cudzysłowu ASCII i Unicode
αғsнιη
2
echo It’s easy | perl -CS -Mutf8 -pe "tr/’/'/"
tchrist

Odpowiedzi:

16

Możesz wypróbować inne narzędzie, takie jak sed:

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

Lub, ponieważ wykonujemy proste tłumaczenie, użyj ypolecenia do sed:

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

GNUtr prawdopodobnie nie działa, ponieważ:

Obecnie w trpełni obsługuje tylko znaki jednobajtowe. W końcu będzie obsługiwać znaki wielobajtowe; kiedy to zrobi, -C opcja spowoduje uzupełnienie zestawu znaków, podczas gdy -c spowoduje uzupełnienie zestawu wartości. To rozróżnienie będzie miało znaczenie tylko wtedy, gdy niektóre wartości nie są znakami, i jest to możliwe tylko w lokalizacjach używających kodowania wielobajtowego, gdy dane wejściowe zawierają błędy kodowania.

I jest postacią wielobajtową:

$ echo -n \' | wc -c
1
$ echo -n  | wc -c  
3
muru
źródło
1
sedjest o wiele ładniejszy dla tego rodzaju pracy.
Kaz Wolfe
2
Aby wyjaśnić ostatnią część dalej: trzastępuje każdy z trzech bajtów osobno ', a więc '''również zepsute sekwencje, w których zastąpił dwa z trzech bajtów podobnymi znakami i . Zamiast tego powinien zrozumieć trzy bajty jako razem oznaczające jeden znak i zamiast tego zastąpić.
deltab
Dla dobrego zrozumienia jest to znak wielobajtowy, możemy również użyć tr -c '[:print:][:cntrl:]' '-'polecenia, aby zastąpić każdy znak , który nie jest drukowany , oprócz prawidłowych znaków kontrolnych, znakiem -. I zobaczysz pojedyncze tłumaczenie na 3 bajty takich znaków ---. dobra uwaga na znak wielobajtowy.
αғsнιη
9

Jeśli chcesz również przekonwertować podwójne cudzysłowy i być może inne znaki, możesz użyć GNUiconv :

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

//TRANSLITPrzyrostek mówi iconv, że dla znaków spoza repertuaru kodowania (tutaj ASCII docelowej), można go zastąpić podobnych znaków lub sekwencji automatycznie. Bez przyrostka iconvpoddaje się, gdy tylko znajdzie nieprzekształcalną postać.

Zauważ, że //TRANSLITwydaje się być rozszerzeniem GNU: POSIXiconv go nie obsługuje.

deltab
źródło
+1. Jeśli konwertujesz tekst z jednego zestawu znaków (lub kodowania) na inny, rozsądne może być użycie narzędzia zaprojektowanego do tego celu.
RedGrittyBrick
@deltab Twoje rozwiązanie zastępuje również podwójne cudzysłowy, których OP nie chce ich zastępować.
αғsнιη
@KasiyA Może powinni.
gerrit
3

Możesz użyć jednego z tych awkrozwiązań:

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

Lub

awk '{gsub(/’/, "'"'"'");print}' file
αғsнιη
źródło
0

Użyj -sopcji tr :

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

Od man tr :

--truncate-set1
          first truncate SET1 to length of SET2
Skippy le Grand Gourou
źródło
1
twoje rozwiązanie zastępuje również podwójne cudzysłowy, których OP nie chce ich zastępować
αғsнιη
Ach, rzeczywiście, dziękuję za zwrócenie na to uwagi. Pozostawię tę odpowiedź w celach informacyjnych.
Skippy le Grand Gourou