tr аналог для символов Unicode?

Мне нужна интернациональная утилита, которая делает то же самое, что и tr : получает символ из потока и заменяет его соответствующим символом. Не требуется конкретное решение, такое как нижнее-верхнее, но общее решение. Без гориллийных звонков, если это возможно.

Обратите внимание, что tr не работает в Linux: он переводит байты, а не символы. Это не удается с многобайтовыми кодировками.

 $ tr --version | head -n 1 tr (GNU coreutils) 8.23 $ echo $LC_CTYPE en_US.UTF-8 $ echo 'Ångstrom' | tr Æ Œ Ņngstrom 

GNU sed работает с многобайтовыми символами. Так:

 $ echo é½Æ | sed 'y/é½Æ/ABŒ/' ABŒ 

Это не так, что GNU tr не был интернационализирован, но он не поддерживает многобайтовые символы (например, не-ASCII в локалях UTF-8). GNU tr будет работать с Æ , Œ до тех пор, пока они будут однобайтными, как в наборе символов iso8859-15.

Подробнее о том, как сделать tr знающим символы не-ascii (unicode)?

В любом случае, это не имеет ничего общего с Linux, речь идет о реализации tr в системе. Независимо от того, использует ли эта система Linux в качестве ядра или tr для Linux или использует API ядра Linux, не имеет значения, поскольку эта часть функций tr имеет место в пользовательском пространстве.

busybox tr и GNU tr наиболее часто встречаются в дистрибутивах программного обеспечения, созданных для Linux, и не поддерживают многобайтовые символы, но есть и другие, которые были перенесены в Linux, например, tr of the geirloom toolchest (портировано из OpenSolaris) или от ast-open, которые делают.

Обратите внимание, что sed s не поддерживает диапазоны, такие как az . Также обратите внимание, что если этот скрипт, содержащий sed 'y/é½Æ/ABŒ/' , написан в кодировке UTF-8, он больше не будет работать так, как ожидалось, если вызывается в локали, где UTF-8 не является кодировкой.

Альтернативой может быть использование perl :

 perl -Mopen=locale -Mutf8 -pe 'y/a-zé½Æ/A-ZABŒ/' 

Выше, perl-код ожидается в UTF-8, но он будет обрабатывать входные данные в кодировке locale (и выводить в том же кодировании). Если он вызывается в локали UTF-8, он транслитерирует UTF-8 Æ (0xc3 0x86) в UTF-8 Œ (0xc5 0x92) и в ISO8859-15, но для 0xc6 -> 0xbc.

В большинстве оболочек наличие этих символов UTF-8 внутри одинарных кавычек должно быть в порядке, даже если скрипт вызывается в локали, где UTF-8 не является кодировкой (исключение – yash который будет жаловаться, если эти байты не образуют действительных символы в локали). Однако, если вы используете другое цитирование, чем одиночные кавычки, это может вызвать проблемы. Например,

 perl -Mopen=locale -Mutf8 -pe "y/♣\`/&'/" 

завершится неудачей в локали, где charset является BIG5-HKSCS, потому что кодировка \ (0x5c) также содержится в некоторых других символах (например, α : 0xa3 0x5c, а кодировка UTF-8 заканчивается на 0xa3 ).

В любом случае, не ожидайте таких вещей, как

 perl -Mopen=locale -Mutf8 -pe 'y/Á-Ź/AZ/' 

работать над устранением острых акцентов. Вышесказанное на самом деле просто

 perl -Mopen=locale -Mutf8 -pe 'y/\x{c1}-\x{179}/\x{41}-\x{5a}/' 

То есть, диапазон основан на кодировке unicode. Таким образом, диапазоны не будут полезны вне четко определенных последовательностей, которые находятся в « правильном » порядке в Unicode, например AZ , 0-9 .

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

 perl -Mopen=locale -MUnicode::Normalize -pe ' $_ = NFKD($_); s/\x{301}//g; $_ = NFKC($_)' 

Это использование форм нормализации Unicode для разложения символов, удаления острых акцентов (здесь объединенная форма U+0301 ) и перекомпоновки.

Другим полезным инструментом для транслитерации Unicode является uconv из ICU . Например, вышесказанное может быть также написано как:

 uconv -x '::NFKD; \u0301>; ::NFKC;' 

Хотя будет работать только с данными UTF-8. Вам понадобится:

 iconv -t utf-8 | uconv -x '::NFKD; \u0301>; ::NFKC;' | iconv -f utf-8 

Уметь обрабатывать данные в локали пользователя.

В Bash вы можете использовать расширение параметра .

Подставляя Å успешно:

 $ string='Hello Ångstrom' $ a='Å' $ b='Œ' $ printf '%s\n' "${string//${a}/${b}}" Hello Œngstrom 

Попытка заменить Æ , который не является частью строки:

 $ string='Hello Ångstrom' $ a='Æ' $ b='Œ' $ printf '%s\n' "${string//${a}/${b}}" Hello Ångstrom