Почему некоторые символы юникода не выводятся на мой терминал?

16

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

Я хочу напечатать символы 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)интерпретируемым escape-последовательностям, а документация для 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 дает греческую альфу с парой диакритических знаков ( точнее , греческая заглавная буква альфа с псили и варией ).

Если вам нужно более шестнадцати битов в вашем побеге Юникода, вам нужно использовать \U, что занимает шестнадцатеричное значение шестнадцати символов: \U0001F0A1даст вам игральную карту.

Draconis
источник
\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 цифр, но это изменилось позже (по моей просьбе).
Стефан