tr: конвертировать апостроф в ASCII

11

Я пытаюсь преобразовать правую одинарную кавычку в апостроф с помощью tr.

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

дан кодированный файл в кодировке UTF-8, aкоторый содержит этот пример:

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

OS X использует BSD trи дает хороший результат:

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

Ubuntu использует GNU trи дает такой неприятный результат:

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

Как я могу выполнить это преобразование в Ubuntu?

plamtrue
источник
Также пробовал: tr $ '\ xE2 \ x80 \ x99' $ '\ x27' <a> b с такими же результатами.
plamtrue
1
Это хорошо знать кавычки ASCII и Unicode
αғsнιη
2
echo It’s easy | perl -CS -Mutf8 -pe "tr/’/'/"
tchrist

Ответы:

16

Вы можете попробовать другой инструмент, например sed:

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

Или, поскольку мы делаем простой перевод, используйте yкоманду для sed:

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

GNUtr не работает предположительно потому что:

В настоящее время trполностью поддерживает только однобайтовые символы. В конце концов он будет поддерживать многобайтовые символы; когда это произойдет, -C опция заставит его дополнить набор символов, тогда как -c заставит его дополнить набор значений. Это различие будет иметь значение только тогда, когда некоторые значения не являются символами, и это возможно только в локалях, использующих многобайтовые кодировки, когда вход содержит ошибки кодирования.

И является многобайтовым символом:

$ echo -n \' | wc -c
1
$ echo -n  | wc -c  
3
Мур
источник
1
sedнамного лучше для такой работы.
Каз Вулф
2
Чтобы пояснить последнюю часть далее: trзаменяется каждый из трех байтов отдельно на ', следовательно, '''также на прерывистые последовательности, где он заменил два из трех байтов аналогичными символами и . Вместо этого следует понимать, что три байта означают один символ, и заменить его вместо этого.
Deltab
Для лучшего понимания это многобайтовый символ, также мы можем использовать tr -c '[:print:][:cntrl:]' '-'команду для замены любого непечатаемого символа , кроме допустимых управляющих символов, на -. И вы увидите один перевод до 3 байтов символов, как ---. хорошая точка для многобайтового символа.
2014 г.
9

Если вы также хотите преобразовать двойные кавычки и, возможно, другие символы, вы можете использовать GNUiconv :

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

//TRANSLITСуффикс говорит , iconvчто для символов вне репертуара целевой кодировки (ASCII) здесь, он может заменить похожие символы или последовательность автоматически. Без суффикса iconvсдастся, как только найдет непереводимый символ.

Обратите внимание, что //TRANSLITэто расширение GNU: POSIXiconv его не поддерживает.

deltab
источник
+1. Если вы конвертируете текст из одного набора символов (или кодировки) в другой, может быть целесообразно использовать инструмент, разработанный для этой цели.
RedGrittyBrick
@deltab ваше решение также заменяет двойные кавычки, которые OP не хочет их заменять.
αғsнιη
@KasiyA Может быть, они должны.
gerrit
3

Вы можете использовать одно из этих awkрешений:

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

Или

awk '{gsub(/’/, "'"'"'");print}' file
αғsнιη
источник
0

Используйте -sопцию tr :

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

От man tr :

--truncate-set1
          first truncate SET1 to length of SET2
Скиппи ле Гран Гуру
источник
1
ваше решение также заменяет двойные кавычки, которые OP не хочет их заменять
αғsнιη
Ах, действительно, спасибо за указание на это. Я оставлю этот ответ для справки.
Скиппи ле Гран Гуру