Pourquoi certains caractères Unicode ne s'impriment-ils pas sur mon terminal?

16

J'utilise Arch Linux avec un terminal simple en utilisant la police Adobe Source Code Pro. Mes paramètres régionaux sont correctement définis sur LANG=en_US.UTF-8.

Je souhaite imprimer des caractères Unicode représentant des cartes à jouer sur mon terminal. J'utilise Wikipedia pour référence .

Les caractères Unicode pour les combinaisons de cartes fonctionnent bien. Par exemple, l'émission

$ printf "\u2660"

imprime un cœur noir à l'écran.

Cependant, j'ai des problèmes avec des cartes à jouer spécifiques. Délivrance

$ printf "\u1F0A1"

imprime le symbole Ἂ1au lieu de l'as de pique 🂡. Qu'est-ce qui ne va pas?

Ce problème persiste sur plusieurs terminaux (urxvt, xterm, termite) et toutes les polices que j'ai essayées (DejaVu, Inconsolata).

Brian Fitzpatrick
la source
Avertissement: si cela est géré par printf, il s'agit d'une amélioration non standard. Ne vous attendez donc pas à ce que de telles évasions fonctionnent. Voir: pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html
schily

Réponses:

27

help printfdiffère printf(1)pour les séquences d'échappement interprétées, et les documents pour GNU printf disent:

printfinterprète deux syntaxes de caractères introduites dans ISO C 99: \upour les caractères Unicode 16 bits (ISO / IEC 10646), spécifiés comme quatre chiffres hexadécimaux hhhh , et \Upour les caractères Unicode 32 bits, spécifiés comme huit chiffres hexadécimaux hhhhhhhhh . printfrenvoie les caractères Unicode en fonction des LC_CTYPEparamètres régionaux. Les caractères Unicode dans les plages U + 0000… U + 009F, U + D800… U + DFFF ne peuvent pas être spécifiés par cette syntaxe, sauf pour U + 0024 ($), U + 0040 (@) et U + 0060 (`) .

Quelque chose de similaire est spécifié dans le manuel Bash pour ANSI C Quoting et echo:

\uHHHH
le caractère Unicode (ISO / IEC 10646) dont la valeur est la valeur hexadécimale HHHH (un à quatre chiffres hexadécimaux)

\UHHHHHHHH
le caractère Unicode (ISO / IEC 10646) dont la valeur est la valeur hexadécimale HHHHHHHH (un à huit chiffres hexadécimaux)

En bref: \un'est pas pour 5 chiffres hexadécimaux. C'est \U:

# printf "\u2660 \u1F0A1 \U1F0A1\n"
 1 🂡
muru
la source
2

La réponse de Muru est complètement correcte, mais juste pour clarifier un point:

Lorsque vous imprimez \u1F0A1, cela est interprété comme un échappement Unicode de seize bits \u1F0A, suivi du caractère littéral 1(puisqu'il \uprend les quatre caractères suivants, ni plus, ni moins). U + 1F0A donne alors , un alpha grec avec deux diacritiques dessus ( lettre majuscule grecque Alpha avec Psili et Varia , pour être précis).

Si vous voulez plus de seize bits dans votre échappement Unicode, vous devez utiliser \U, ce qui prend la valeur de hex de huit caractères: \U0001F0A1vous donnera la carte à jouer.

Draconis
la source
\U0001F0A1est en fait plus portable que \U1F0A1. C'est l' printfutilitaire GNU autonome qui a introduit ces séquences \uXXXX/ \UXXXXXXXXet il nécessite 4 chiffres pour \uet 8 pour \U. D'autres printfimplémentations comme le shell intégré GNU, ksh93 et ​​zsh sont plus laxistes. En tout cas ce printf '\u/\U'n'est pas POSIX. POSIX va cependant spécifier des zsh $'\U1F0A1'et ne nécessitera pas les 8 chiffres.
Stéphane Chazelas
@ StéphaneChazelas Intéressant, j'avais toujours pensé que POSIX irait avec celui à huit chiffres. Je suppose que la version à huit chiffres est toujours valide en zsh si vous voulez éviter de capturer des lettres et des chiffres supplémentaires après le code?
Draconis
Oui, \uxxxxest jusqu'à 4 chiffres et \Uxxxxxxxxest jusqu'à 8 chiffres. Notez que Unicode est désormais limité aux points de code 0 à 0x10FFFF (une limitation apportée par UTF16), de sorte que les points de code n'auront jamais plus de 6 chiffres (toujours \U123456789serait interprété comme le caractère du point de code 0x12345678 suivi 9et échoué). La spécification POSIX pour $'\u\U'n'est toujours pas finalisée (voir austingroupbugs.net/view.php?id=249 ). Dans une version antérieure, ils exigeaient tous les 4/8 chiffres, mais cela a changé plus tard (à ma demande).
Stéphane Chazelas