tr: преобразовать апостроф в ASCII

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

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

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

We’re 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?

4 ответа

Решение

Вы можете попробовать другой инструмент, например, 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

Если вы также хотите преобразовать двойные кавычки и, возможно, другие символы, вы можете использовать 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 не поддерживает это.

Вы можете использовать один из этих 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 вариант 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
Другие вопросы по тегам