Чому деякі символи unicode не друкуються на мій термінал?


16

Я запускаю Arch Linux із простим терміналом, використовуючи шрифт Adobe Source Code Pro. Моя мова налаштована правильно LANG=en_US.UTF-8.

Я хочу надрукувати символи Unicode, що представляють гральні карти до мого терміналу. Я використовую Вікіпедію для довідки .

Символи Unicode для підходів для карт добре працюють. Наприклад, видача

$ printf "\u2660"

виводить на екран чорне серце.

Однак у мене виникають проблеми з конкретними гральними картами. Видача

$ printf "\u1F0A1"

друкує символ Ἂ1замість лопат туза 🂡. Що відбувається не так?

Ця проблема зберігається через декілька терміналів (urxvt, xterm, termite) і кожного шрифту, який я випробував (DejaVu, Inconsolata).


Попередження: якщо цим керує printf, це нестандартне вдосконалення. Тому взагалі не сподівайтесь, що такі втечі спрацюють. Дивіться: pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html
schily

Відповіді:


27

help printfвідкладає printf(1)для інтерпретованих послідовностей евакуації, а документи для GNU printf говорить:

printfінтерпретує два синтаксиси символів, введені в ISO C 99: \uдля 16-бітових символів Unicode (ISO / IEC 10646), вказаних чотирма шістнадцятковими цифрами hhhh , і \Uдля 32-бітових символів Unicode, зазначених як вісім шістнадцяткових цифр hhhhhhhh . printfвиводить символи Unicode відповідно до LC_CTYPEмісцевості. Символи Unicode у діапазонах U + 0000… U + 009F, U + D800… U + DFFF не можуть бути визначені цим синтаксисом, за винятком U + 0024 ($), U + 0040 (@) та U + 0060 (`) .

Щось подібне вказано в посібнику Bash для цитування ANSI C та echo:

\uHHHH
символ Unicode (ISO / IEC 10646), значення якого - шістнадцяткове значення HHHH (одна-чотири шістнадцяткові цифри)

\UHHHHHHHH
символ Unicode (ISO / IEC 10646), значення якого - шістнадцяткове значення HHHHHHHH (одна-вісім шістнадцяткових цифр)

Якщо коротко: \uне для 5-ти шістнадцяткових цифр. Це \U:

# printf "\u2660 \u1F0A1 \U1F0A1\n"
 1 🂡

2

Відповідь Муру є абсолютно правильною, але просто для уточнення одного моменту:

Коли ви друкуєте \u1F0A1, це інтерпретується як шістнадцятибітовий втечу Unicode \u1F0A, за яким слідує буквальний символ 1(оскільки \uзаймає наступні чотири символи, ні більше, ні менше). Потім U + 1F0A дає грецьку альфу з парою діакритики ( грецька велика літера Альфа з Псилі та Варією , якщо бути точним).

Якщо ви хочете більше, ніж шістнадцять біт у своєму втечі Unicode, вам потрібно скористатися \U, яке має шістнадцять значень у вісім символів: \U0001F0A1дасть вам ігрову карту.


\U0001F0A1насправді більш портативний, ніж \U1F0A1. Це автономна printfутиліта GNU, яка вперше представила ці \uXXXX/ \UXXXXXXXXпослідовності, і для цього потрібно 4 цифри для \uта 8 для \U. Інші printfреалізації, такі як вбудована оболонка GNU, ksh93 та zsh, є більш розрядженими. У будь-якому випадку printf '\u/\U'це не POSIX. Однак POSIX збирається вказати zsh $'\U1F0A1'та не вимагатиме всіх 8 цифр.
Стефан Шазелас

@ StéphaneChazelas Цікаво, я завжди вважав, що POSIX піде з восьмизначним. Я припускаю, що восьмизначна версія все ще діє в zsh, якщо ви хочете уникати зайвих літер і цифр після коду?
Драконіс

Так, \uxxxxце до 4 -х цифр і \Uxxxxxxxxстановить до 8 цифр. Зауважте, що Unicode тепер обмежений кодовими точками від 0 до 0x10FFFF (обмеження, введені UTF16), тому кодові точки ніколи не матимуть більше 6 цифр (все-таки \U123456789інтерпретується як символ точки коду 0x12345678 з подальшим 9і невдалим). Специфікація POSIX $'\u\U'досі не остаточно доопрацьована (див. Austingroupbugs.net/view.php?id=249 ). У попередньому проекті вони вимагали всіх 4/8 цифр, але згодом вони змінилися (на мій запит).
Стефан Шазелас
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.