Perché alcuni caratteri Unicode non vengono stampati sul mio terminale?


16

Sto eseguendo Arch Linux con un semplice terminale usando il carattere Adobe Source Code Pro. La mia lingua è impostata correttamente su LANG=en_US.UTF-8.

Voglio stampare personaggi Unicode che rappresentano carte da gioco sul mio terminale. Sto usando Wikipedia come riferimento .

I personaggi Unicode per i semi delle carte funzionano bene. Ad esempio, emissione

$ printf "\u2660"

stampa un cuore nero sullo schermo.

Tuttavia, ho problemi con carte da gioco specifiche. emittente

$ printf "\u1F0A1"

stampa il simbolo Ἂ1anziché l'asso di picche 🂡. Cosa non va?

Questo problema persiste su diversi terminali (urxvt, xterm, termite) e tutti i font che ho provato (DejaVu, Inconsolata).


Avvertenza: se questo è gestito da printf, si tratta di un miglioramento non standard. Quindi non aspettarti che tali fughe funzionino affatto. Vedi: pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html
Schily

Risposte:


27

help printffa riferimento a printf(1)per le sequenze di escape interpretate e i documenti per GNU printf dicono:

printfinterpreta due sintassi di caratteri introdotte in ISO C 99: \uper caratteri Unicode a 16 bit (ISO / IEC 10646), specificati come quattro cifre esadecimali hhhh , e \Uper caratteri Unicode a 32 bit, specificati come otto cifre esadecimali hhhhhhhhh . printfgenera i caratteri Unicode in base alla LC_CTYPElocale. Caratteri Unicode negli intervalli U + 0000… U + 009F, U + D800… U + DFFF non possono essere specificati da questa sintassi, ad eccezione di U + 0024 ($), U + 0040 (@) e U + 0060 (`) .

Qualcosa di simile è specificato nel manuale di Bash per la quotazione ANSI C e echo:

\uHHHH
il carattere Unicode (ISO / IEC 10646) il cui valore è il valore esadecimale HHHH (da una a quattro cifre esadecimali)

\UHHHHHHHH
il carattere Unicode (ISO / IEC 10646) il cui valore è il valore esadecimale HHHHHHHH (da una a otto cifre esadecimali)

In breve: \unon è per 5 cifre esadecimali. È \U:

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

2

La risposta di Muru è completamente corretta, ma solo per chiarire un punto:

Quando stampi \u1F0A1, viene interpretato come una fuga Unicode a sedici bit \u1F0A, seguita dal carattere letterale 1(poiché \uprende i seguenti quattro caratteri, niente di più, niente di meno). U + 1F0A quindi dà , un alfa greca con un paio di segni diacritici su di esso ( Alpha Capital Greek Letter con Psili e Varia , per essere precisi).

Se vuoi più di sedici bit nella tua fuga Unicode, devi usare \U, che richiede un esagono di otto caratteri: \U0001F0A1ti darà la carta da gioco.


\U0001F0A1è in realtà più portatile di \U1F0A1. È l' printfutilità autonoma GNU che ha introdotto per la prima volta quelle \uXXXX/ \UXXXXXXXXsequenze e richiede 4 cifre per \ue 8 per \U. Altre printfimplementazioni come l'integrato della shell GNU, ksh93 e zsh sono più rilassate. In ogni caso printf '\u/\U'non è POSIX. POSIX specificherà comunque zsh $'\U1F0A1'e non richiederà tutte e 8 le cifre.
Stéphane Chazelas,

@ StéphaneChazelas Interessante, avevo sempre pensato che POSIX sarebbe andato con quello a otto cifre. Presumo che la versione di otto cifre sia ancora valida in zsh se si desidera evitare di acquisire lettere e numeri extra dopo il codice?
Draconis,

Sì, \uxxxxè fino a 4 cifre ed \Uxxxxxxxxè fino a 8 cifre. Nota che Unicode ora è limitato ai punti di codice da 0 a 0x10FFFF (una limitazione introdotta da UTF16), quindi i punti di codice non avranno mai più di 6 cifre ( \U123456789verrebbero comunque interpretati come il carattere del punto di codice 0x12345678 seguito 9e fallito). Le specifiche POSIX per non $'\u\U'sono ancora state finalizzate (vedi austingroupbugs.net/view.php?id=249 ). In una bozza precedente, richiedevano tutte le 4/8 cifre, ma ciò è cambiato in seguito (su mia richiesta).
Stéphane Chazelas,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.