Warum werden einige Unicode-Zeichen nicht auf meinem Terminal gedruckt?


16

Ich verwende Arch Linux mit einem einfachen Terminal und der Schriftart Adobe Source Code Pro. Mein Gebietsschema ist korrekt eingestellt auf LANG=en_US.UTF-8.

Ich möchte Unicode-Zeichen für Spielkarten auf meinem Terminal drucken. Ich verwende Wikipedia als Referenz .

Die Unicode-Zeichen für Karten passen gut. Zum Beispiel beim Ausstellen

$ printf "\u2660"

druckt ein schwarzes Herz auf den Bildschirm.

Ich habe jedoch Probleme mit bestimmten Spielkarten. Ausgabe

$ printf "\u1F0A1"

druckt das Symbol Ἂ1anstelle des Pik-As 🂡. Was läuft falsch?

Dieses Problem besteht weiterhin auf mehreren Terminals (urxvt, xterm, termite) und allen von mir getesteten Schriftarten (DejaVu, Inconsolata).


Warnung: Wenn dies von printf behandelt wird, handelt es sich um eine nicht standardmäßige Erweiterung. Erwarten Sie also nicht, dass solche Fluchten überhaupt funktionieren. Siehe: pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html
schily

Antworten:


27

help printfverzögert sich printf(1)für die interpretierten Escape-Sequenzen, und die Dokumentation für GNU printf sagt:

printf99 eingeführt interpretiert zwei Zeichen Syntaxen in ISO C: \ufür 16-Bit - Unicode (ISO / IEC 10646) Zeichen, angegeben als vier hexadezimale Ziffern hhhh , und \Ufür 32-Bit - Unicode - Zeichen, wie acht Hexadezimalziffern angegeben hhhhhhhh . printfgibt die Unicode-Zeichen entsprechend dem LC_CTYPEGebietsschema aus. Unicode-Zeichen in den Bereichen U + 0000… U + 009F, U + D800… U + DFFF können mit dieser Syntax nicht angegeben werden, mit Ausnahme von U + 0024 ($), U + 0040 (@) und U + 0060 (`). .

Ähnliches ist im Bash-Handbuch für ANSI C Quoting angegeben und echo:

\uHHHH
das Unicode-Zeichen (ISO / IEC 10646), dessen Wert der Hexadezimalwert HHHH ist (ein bis vier Hexadezimalziffern )

\UHHHHHHHH
das Unicode-Zeichen (ISO / IEC 10646), dessen Wert der Hexadezimalwert ist HHHHHHHH (eine bis acht Hexadezimalziffern )

Kurz gesagt: \uist nicht für 5 Hex-Ziffern. Es ist \U:

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

2

Murus Antwort ist völlig richtig, um nur einen Punkt zu verdeutlichen:

Beim Drucken \u1F0A1wird dies als 16-Bit-Unicode-Escape interpretiert \u1F0A, gefolgt vom Literalzeichen 1(da \udie folgenden vier Zeichen verwendet werden, nicht mehr und nicht weniger). U + 1F0A ergibt dann ein griechisches Alpha mit ein paar diakritischen Zeichen ( griechischer Großbuchstabe Alpha mit Psili und Varia , um genau zu sein).

Wenn Sie mehr als sechzehn Bits für Ihre Unicode-Escape-Funktion verwenden möchten, müssen Sie \UFolgendes verwenden: Hexadezimaler Wert von acht Zeichen: Gibt Ihnen die \U0001F0A1Spielkarte.


\U0001F0A1ist eigentlich tragbarer als \U1F0A1. Es ist das GNU-Standalone- printfDienstprogramm, das diese \uXXXX/ \UXXXXXXXXSequenzen zuerst eingeführt hat, und es erfordert 4 Ziffern für \uund 8 für \U. Andere printfImplementierungen wie das Built-in der GNU-Shell, ksh93 und zsh, sind lockerer. In jedem Fall printf '\u/\U'handelt es sich nicht um POSIX. POSIX spezifiziert jedoch zshs $'\U1F0A1'und benötigt nicht alle 8 Ziffern.
Stéphane Chazelas

@ StéphaneChazelas Interessanterweise hatte ich immer gedacht, dass POSIX mit der achtstelligen Zahl mithalten würde. Ich gehe davon aus, dass die achtstellige Version in zsh noch gültig ist, wenn Sie vermeiden möchten, zusätzliche Buchstaben und Zahlen nach dem Code zu erfassen.
Draconis

Ja, \uxxxxist bis zu 4 Ziffern und \Uxxxxxxxxist bis zu 8 Ziffern. Beachten Sie, dass Unicode jetzt auf die Codepunkte 0 bis 0x10FFFF beschränkt ist (eine Einschränkung durch UTF16), sodass Codepunkte nie mehr als 6 Stellen haben (sie werden immer \U123456789noch als Zeichen des Codepunkts 0x12345678 interpretiert, gefolgt von 9und schlagen fehl). Die POSIX-Spezifikation für $'\u\U'ist noch nicht fertiggestellt (siehe austingroupbugs.net/view.php?id=249 ). In einem früheren Entwurf waren alle 4/8-Stellen erforderlich, dies wurde jedoch später geändert (auf meine Anfrage).
Stéphane Chazelas
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.