Як кажучи, як я можу перетворити Unicode Codepoint [0-9A-F] в символ для друку?


23

У мене є список кодових точок Unicode, але я не знаю про "простий" спосіб перетворення цих шестигранних значень у фактичні символи, які вони представляють ...

Я чув, що zsh має echo -e '\u0965', але я використовую bash 4.1.

Чи є щось таке просте, як метод zsh, для bash?


Відповіді:


16

Ви можете використовувати ехо bash або / bin / echo з GNU coreutils у поєднанні з iconv:

echo -ne '\x09\x65' | iconv -f utf-16be

За замовчуванням iconv перетворюється на кодування локалів. Можливо, більш портативним, ніж покладатися на певну оболонку чи команду ехо, - це Perl. Більшість будь-якої системи UNIX, про яку я знаю, хоча Perl є в наявності, і вона навіть має кілька портів Windows.

perl -C -e 'print chr 0x0965'

Більшу частину часу, коли мені потрібно це зробити, я перебуваю в такому редакторі, як Vim / GVim, який має вбудовану підтримку. Перебуваючи у режимі вставки, натисніть Ctrl-V, а потім u, а потім введіть чотири шістнадцяткових символів. Якщо ви хочете, щоб символ перевищував U + FFFF, використовуйте великі букви U та введіть 8 шістнадцяткових символів. Vim також підтримує користувальницький простий у створенні клавіатури. Він перетворює ряд символів в інший символ. Наприклад, у мене є розроблена карта клавіш, яка називається www, вона перетворює TM в ™, (C) з ©, (R) в ® і так далі. Я також маю ключову карту для Klingon, коли це стає необхідним. Я впевнений, що Emacs має щось подібне. Якщо ви користуєтесь додатком GTK +, який включає GVim та термінал GNOME, ви можете спробувати Control-Shift-u, а потім 4 шістнадцяткові символи, щоб створити символ Unicode. Я впевнений, що KDE / Qt має щось подібне.

ОНОВЛЕННЯ: Станом на Bash 4.2, зараз, здається, є вбудована функція:

echo $'\u0965'

ОНОВЛЕННЯ: Також, на сьогодні, приклад Python, мабуть, буде кращим для Perl. Це працює в Python 2 і 3:

python -c 'print(u"\u0965")'

Дякую ... хороший і лаконічний, але мене трохи спантеличено, як він знає, як трактувати значення як UTF-16BE .. Я думаю, що це означає "chr" ...
Peter.O

@fred, це хороший момент. Приклад Perl чутливий до мови. -C забезпечує повну обробку Unicode, але приклад працює, тому що мій локал використовує приклад Unicode. Якщо я встановив LANG на C, я отримую попередження про широкий символ друку, але він все ще друкує. Якщо я друкую chr 0xa2в локалі UTF-8, я отримую знак цента ¢, але якщо я використовую LANG = C, я отримую , оскільки він виводить байт 0xa2, який недійсний у UTF-8. Приклад Vim / GVim напівчутливий до локальної точки. Правильніше, до кодування файлу. Якщо ви запустили Vim в не-UTF-8 місцевості, вам потрібно буде:set encoding=utf-8
penguin359

@fred Я повинен зазначити, Perl трактує значення chr як кодову точку Unicode, якщо Perl запускається в локальній локації Unicode, як UTF-8. Кодова точка - це унікальне число, яке представляє символ і не прив’язане до жодного кодування, наприклад UTF-16BE або UTF-8. Він перетворює його в правильне кодування, коли він роздруковує його. Наприклад, клинопис Знак A - кодова точка U + 012000. Я можу використовувати chr 0x12000в Perl (якщо Unicode активний) для його представлення. У UTF-16BE це 0xd8, 0x08, 0xdc та 0x00. Ви символом є U + 0965, який, як буває, є байтами 0x09, а потім Ux-16BE.
penguin359

@ penguin359 .. Дякую, одного разу (сподіваюсь) я добре погляну на perl .. Це здається незрозуміло загадковим, але тоді так зробили sed і regex, спочатку, а зараз це досить просто ... можливо, це трохи як вим; крута крива навчання, потім звичайний плавання .... Добре прочитати ваші пояснення ... це прокладає шлях ..
Peter.O

Я щойно (повторно) виявив, що думка printf Steven D не буде обробляти блок ASCII діапазону Юнікод, тому ваша perlвідповідь зараз найкраща (для моїх конкретних вимог). Я раніше виключав printf (місяці тому) , але я забув про це. Ось квест / відповідь про його межі ... Чому printf повідомляє про помилку на всіх, окрім трьох (ASCII-діапазон)
кодових точок

13

Bash 4.2 (випущена в 2011 році) додана підтримка echo -e '\u0965', printf '\u0965', printf %b '\u0965'і echo $'\u0965'також працювати.

http://tiswww.case.edu/php/chet/bash/FAQ :

o   $'...', echo, and printf understand \uXXXX and \UXXXXXXXX escape sequences.

Дякую ... Я все ще в основному використовую bash 4.1.5 в Ubuntu 10.04, але, безумовно, добре знати, що тепер він доступний в 4.2. (+1)
Пітер.О

1
+1; зауважте, що у bash 4.2.xверсіях є помилка, де значення між 0x80та 0xff( 128 - 255) - тобто в розширеному діапазоні ASCII - НЕ правильно кодуються UTF8, а замість цього просто проходять через це, що призводить до недійсного UTF8 char, який деякі термінали представляють як ?. Станом на (принаймні) 4.3.11це було виправлено; якщо echo $'\ued'робить í, то помилка є НЕ присутній.
mklement0

5

Якщо у вас є GNU coreutils, спробуйте printf:

$ printf '\u0965\n'

echo може виконати роботу, якщо у вашій консолі використовується UTF-8 і у вас є кодування UTF-8:

$ echo -e '\xE0\xA5\xA5'

Таблицю шістнадцяткових кодувань Unicode до UTF-8 ви можете знайти тут: http://www.utf8-chartable.de/ . Можна перетворити кодові точки Unicode в шістнадцяткові, використовуючи ряд мов скриптування. Ось приклад використання python:

python -c "print(unichr(int('0965', 16)).encode('utf-8').encode('hex'))"

Далі йде сценарій Perl, який перетворить аргументи у правильне шістнадцяткове значення (тут багато непотрібних дужок):

#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Encode;

foreach (@ARGV) {
    say unpack('H*', encode('utf8', chr(hex($_))))
}

Наприклад,

./uni2utf 0965
e0a5a5

Звичайно, якщо у вас є Perl або Python, ви також можете просто використовувати їх для друку символів.


Дякую .. Не echoбуду робити те, що я хочу, так як Codepoints - це 2-байтний UTF-16 Big-Endian .. але ви нагадали мені, що є 2 функції printf! (Я думав, що printf може це зробити, і здається, що я посилаюсь на неправильний) ... $(which printf)працює ... Дякую за приклад python .. але за це (моя крива навчання) я намагаюся дотримуватися якнайближче по можливості «Баш» , як тільки scriting мову залучений .. (коли я досить комфортно з Баш, я застряють в Python ... до речі, .encode('hex')це один крок за те , що мені потрібно .. (я думав , що це виглядало трохи зайнятий там :)
Peter.O

Так. Радий, що принаймні частина цього була корисною.
Стівен Д

Я щойно бачив, як ти знайдеш фрагмент perl .. дякую ... добре, що ці різні рішення подано на розгляд ... Printf - це саме те, що я шукав (одна команда, як на прикладі zsh) ... .. Я можу добре розмістити свій не використовуючий інший метод скриптового мови, який працює над потоком шістнадцяткових даних (ні \ u тощо).
Peter.O

Мені особливо подобається стислість printfвищезазначеного, але воно не справляється зі значеннями нижче `` \ u00A0 ... I've just re-discovered something I already knew (but dropped off the radar)... Here is a Question I asked about 4 months ago; [Why does printf report an error on all but three (ASCII-range) Unicode Codepoints](http://askubuntu.com/questions/20806/why-does-printf-report-an-error-on-all-but-three-ascii-range-unicode-codepoints)... So *penguin359's* perl` рішення виглядає зараз досить добре :) .. Це єдиний вивідок, і я після "простого введення", тому я дам йому зелений perl
галочок

2

UPDATE: Ось Баш спосіб зробити одне значення Unicode ... (по «Баш» Я маю в виду: не використовувати будь-який інший мову сценаріїв) .. спасибі Жиль для suggeston в цьому askubuntu Q / A .
За цим посиланням : recode (Застаріло iconv, dos2unix, unix2dos) .. Редагувати: але відповідно до коментаря нижче, "застарілі" можуть просто означати "альтернативні"

      echo -n 0x0965 |recode UTF-16BE/x4..UTF-8

Ось метод обробки необробленого шістнадцяткового дампа як вхідного (тобто ніяких уникнутих префіксів типу; \ u0965 та no \ x09 \ x65) ..
xxd- це утиліта з шестигранним дампам (у комплекті vim-common), яка може відновити неочищений шістнадцятковий дамп для символів, які дамп представляє ... Кодові точки Unicode - це UTF-16BigEndian, що саме є шестнадцятковим дамп ..
xxdу режимі повернення приймає потік значень Hex із розривами рядків, які ігноруються.

Цей скрипт створює потік UTF-16BE, який потім повертається до початкових символів.
Останній рядок містить дві необхідні команди; xxdіiconv

for line in \
  "Matsuo Basho (1644-1694)" \
  "  pond" \
  "  frog jumps in" \
  "  plop!"
do 
  echo "$line" |iconv -f "$(locale charmap)" -t "UTF-16BE" |xxd -ps -u 
done |
#    (---this is the **revert** code---) 
tee >(xxd -p -u -r |iconv -f "UTF-16BE") ;echo

Ось вихід (спочатку показується шестигранний вхід UTF-16BE).
Примітка; xxdсегментує власний вихід з новим рядком на 60 шістнадцяткових цифр ... Опція повернення ігнорує ці нові рядки .. вона ігнорує будь-які / всі нові рядки (як це не шістнадцяткові цифри) ..

004D0061007400730075006F00200042006100730068006F002000280031
003600340034002D00310036003900340029000A
002000200070006F006E0064000A
0020002000660072006F00670020006A0075006D0070007300200069006E
000A
002000200070006C006F00700021000A

Matsuo Basho (1644-1694)
  pond
  frog jumps in
  plop!

Оскільки, здається, ви використовували інформацію у пінгвіні359 у своїй відповіді, ви можете розглянути можливість її відповіді правильною, а не моєю.
Стівен D

@Steven D: вагомий коментар, але "здається" - це оперативне слово. Я вже декілька днів використовую подібний iconv, що мене здивувало, чи є одна команда. Я робив подібну обробку цілих файлів у Windows (C ++), тому у мене є розумне розуміння Unicode. Я дійсно був після швидкого і простого bashметоду. Під "bash" я маю на увазі: використання мови сценаріїв bash; не python / perl зсередини bash). Я додав це як відповідь, оскільки це може бути корисно тому, хто читає цю сторінку. Це хороший однофайл для цілого файлу. Твоя printfнайкраща відповідь для мене.
Пітер.O

2
Я б не сказав, що recode застаріває iconv, насправді recode старший ніж iconv, і в наші дні iconv набагато частіше встановлюється за замовчуванням, ніж recode (наприклад, в Linux, iconv майже завжди встановлюється, оскільки він постачається з libc).
Жил 'ТАК - перестань бути злим'

Дякую .. Мені було цікаво про це .. Ця веб-сторінка не є точно остаточним посиланням ... тож це більше альтернатива ...
Peter.O

1

Якщо припустимо, що для вашої ОС кодування за замовчуванням є UTF-8 (справедливо для більшості поточних дистрибутивів), ви можете використовувати bash безпосередньо для перетворення будь-якої точки коду UNICODE:

echo -e "Unicode Character 'DEVANAGARI DOUBLE DANDA' (U+0965) \U0965"

Звичайно, глиф з’явиться правильно, лише якщо у вас є правильний шрифт. Станом на bash 4.3 всі кодові точки працюватимуть правильно. І ці два вбудовані варіанти також працюватимуть:

printf "%b" "Unicode Character (U+0965) \U0965 \n"
echo $'Unicode Character (U+0965) \U0965'

Зауважте, що для bash 4.2 точки коду Unicode від 0x80до 0xFFкодуються неправильно (помилка bash). Щоб вирішити цю проблему, ви повинні ознайомитись з програмою на цьому веб-сайті (також добре для глибокого вивчення проблеми перетворення чисел у символи).


Для мене працює в bash 4.3 і zsh. Чи є звіт про помилку для bash 4.2, на який ви можете посилатися?
Мікель

це виглядає на мене як на правильну помилку: https://lists.gnu.org/archive/html/bug-bash/2012-02/msg00035.htmlОпис: \ u та \ U неправильно кодують значення між \ u80 та \ uff

0

Використання підстановки шаблону у версії 4.2 (і вище) bash:

${parameter/pattern/string}

як описано тут http://steve-parker.org/sh/tips/pattern-substitution/

UNICODE_HEX="U+02211"
printf ${UNICODE_HEX/U+/"\U"}


UNICODE_HEX="U+03BB"
printf ${UNICODE_HEX/U+/"\U"}
λ         

1
Зауважте, що, як зазначено в попередній відповіді , це працює лише у версії 4.2 (і вище). Насправді це додає порівняно небагато попередньої відповіді.
G-Man каже: "Відновити Моніку"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.