¿Por qué no se imprimen algunos caracteres Unicode en mi terminal?

16

Estoy ejecutando Arch Linux con terminal simple usando la fuente Adobe Source Code Pro. Mi configuración regional está configurada correctamente LANG=en_US.UTF-8.

Quiero imprimir caracteres Unicode que representan naipes en mi terminal. Estoy usando Wikipedia como referencia .

Los caracteres Unicode para trajes de cartas funcionan bien. Por ejemplo, emitiendo

$ printf "\u2660"

imprime un corazón negro en la pantalla.

Sin embargo, estoy teniendo problemas con cartas específicas. Emisor

$ printf "\u1F0A1"

imprime el símbolo en Ἂ1lugar del as de espadas 🂡. Que va mal

Este problema persiste en varios terminales (urxvt, xterm, termite) y en todas las fuentes que he probado (DejaVu, Inconsolata).

Brian Fitzpatrick
fuente
Advertencia: si esto es manejado por printf, es una mejora no estándar. Así que no esperes que tales escapes funcionen en absoluto. Ver: pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html
schily

Respuestas:

27

help printfdifiere printf(1)para las secuencias de escape interpretadas, y los documentos para GNU printf dicen:

printfinterpreta las sintaxis de dos caracteres introducidas en ISO C 99: \upara caracteres Unicode de 16 bits (ISO / IEC 10646), especificados como cuatro dígitos hexadecimales hhhh , y \Upara caracteres Unicode de 32 bits, especificados como ocho dígitos hexadecimales hhhhhhhh . printfgenera los caracteres Unicode de acuerdo con la LC_CTYPEconfiguración regional. Los caracteres Unicode en los rangos U + 0000 ... U + 009F, U + D800 ... U + DFFF no pueden especificarse mediante esta sintaxis, excepto U + 0024 ($), U + 0040 (@) y U + 0060 (`) .

Algo similar se especifica en el manual Bash para ANSI C Quoting y echo:

\uHHHH
el carácter Unicode (ISO / IEC 10646) cuyo valor es el valor hexadecimal HHHH (de uno a cuatro dígitos hexadecimales)

\UHHHHHHHH
el carácter Unicode (ISO / IEC 10646) cuyo valor es el valor hexadecimal HHHHHHHH (de uno a ocho dígitos hexadecimales)

En resumen: \uno es para 5 dígitos hexadecimales. Es \U:

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

La respuesta de Muru es completamente correcta, pero solo para aclarar un punto:

Cuando imprime \u1F0A1, se interpreta como un escape Unicode de dieciséis bits \u1F0A, seguido del carácter literal 1(ya que \utoma los siguientes cuatro caracteres, ni más, ni menos). U + 1F0A a continuación, da , una alfa griega con un par de diacríticos en él ( griego Mayúscula alfa con Psili y Varia , para ser exactos).

Si quieres más de dieciséis bits en tu escape de Unicode, debes usarlo \U, que requiere un hexadecimal de ocho caracteres: \U0001F0A1te dará la carta de juego.

Draconis
fuente
\U0001F0A1en realidad es más portátil que \U1F0A1. Es la printfutilidad independiente de GNU que introdujo esas \uXXXX/ \UXXXXXXXXsecuencias por primera vez y requiere 4 dígitos para \uy 8 para \U. Otras printfimplementaciones como la construcción del shell GNU, ksh93 y zsh son más laxas. En cualquier caso printf '\u/\U'no es POSIX. Sin embargo, POSIX especificará zsh $'\U1F0A1'y no requerirá los 8 dígitos.
Stéphane Chazelas
@ StéphaneChazelas Interesante, siempre pensé que POSIX iría con el de ocho dígitos. Supongo que la versión de ocho dígitos sigue siendo válida en zsh si desea evitar capturar letras y números adicionales después del código.
Draconis
Sí, \uxxxxtiene hasta 4 dígitos y \Uxxxxxxxxtiene hasta 8 dígitos. Tenga en cuenta que Unicode ahora está limitado a los puntos de código 0 a 0x10FFFF (una limitación traída por UTF16), por lo que los puntos de código nunca tendrán más de 6 dígitos (aún \U123456789se interpretarían como el carácter del punto de código 0x12345678 seguido de 9y fallará). La especificación POSIX para $'\u\U'todavía no está finalizada (ver austingroupbugs.net/view.php?id=249 ). En un borrador anterior, requerían todos los dígitos de 4/8 pero eso cambió más tarde (a petición mía).
Stéphane Chazelas