Mengapa beberapa karakter unicode tidak akan mencetak ke terminal saya?

16

Saya menjalankan Arch Linux dengan terminal sederhana menggunakan font Adobe Source Code Pro. Lokal saya diatur dengan benar ke LANG=en_US.UTF-8.

Saya ingin mencetak karakter Unicode yang mewakili kartu bermain ke terminal saya. Saya menggunakan Wikipedia untuk referensi .

Karakter Unicode untuk setelan kartu berfungsi dengan baik. Misalnya, menerbitkan

$ printf "\u2660"

mencetak hati hitam ke layar.

Namun, saya mengalami masalah dengan kartu remi tertentu. Penerbitan

$ printf "\u1F0A1"

mencetak simbol Ἂ1sebagai ganti kartu as 🂡. Apa yang salah?

Masalah ini tetap ada di beberapa terminal (urxvt, xterm, rayap) dan setiap font yang saya coba (DejaVu, Inconsolata).

Brian Fitzpatrick
sumber
Peringatan: jika ini ditangani oleh printf, itu adalah peningkatan non-standar. Jadi jangan berharap pelarian seperti itu bekerja sama sekali. Lihat: pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html
schily

Jawaban:

27

help printfDefers to printf(1)for the escape sequence ditafsirkan, dan dokumen untuk GNU printf mengatakan:

printfmenafsirkan dua sintaks karakter yang diperkenalkan dalam ISO C 99: \uuntuk karakter Unicode 16-bit (ISO / IEC 10646), ditetapkan sebagai empat digit heksadesimal hhhh , dan \Uuntuk karakter Unicode 32-bit, ditetapkan sebagai delapan digit heksadesimal hhhhhhhh . printfmenampilkan karakter Unicode sesuai dengan LC_CTYPElokal. Karakter Unicode dalam rentang U + 0000 ... U + 009F, U + D800 ... U + DFFF tidak dapat ditentukan oleh sintaks ini, kecuali untuk U + 0024 ($), U + 0040 (@), dan U + 0060 (`) .

Sesuatu yang serupa ditentukan dalam manual Bash untuk ANSI C Quoting dan echo:

\uHHHH
karakter Unicode (ISO / IEC 10646) yang nilainya adalah nilai heksadesimal HHHH (satu hingga empat digit hex)

\UHHHHHHHH
karakter Unicode (ISO / IEC 10646) yang nilainya adalah nilai heksadesimal HHHHHHHHH (satu hingga delapan digit hex)

Singkatnya: \ubukan untuk 5 digit hex. Itu \U:

# printf "\u2660 \u1F0A1 \U1F0A1\n"
♠ Ἂ1 🂡
muru
sumber
2

Jawaban Muru sepenuhnya benar, tetapi hanya untuk memperjelas satu hal:

Saat Anda mencetak \u1F0A1, itu ditafsirkan sebagai pelarian Unicode enam belas-bit \u1F0A, diikuti oleh karakter literal 1(karena \umengambil empat karakter berikut , tidak lebih, tidak kurang). U + 1F0A kemudian memberikan Ἂ, alfa Yunani dengan beberapa diakritik di atasnya ( Huruf Ibrani Yunani dengan Psili dan Varia , tepatnya).

Jika Anda ingin lebih dari enam belas bit dalam pelarian Unicode Anda, Anda perlu menggunakan \U, yang membutuhkan hex delapan karakter: \U0001F0A1akan memberi Anda kartu bermain.

Draconis
sumber
\U0001F0A1sebenarnya lebih portabel daripada \U1F0A1. Ini adalah printfutilitas mandiri GNU yang pertama kali memperkenalkan mereka \uXXXX/ \UXXXXXXXXurutan dan memang membutuhkan 4 digit untuk \udan 8 untuk \U. printfImplementasi lain seperti built-in dari GNU shell, ksh93 dan zsh lebih longgar. Bagaimanapun printf '\u/\U'juga bukan POSIX. Namun POSIX akan menentukan zsh $'\U1F0A1'dan tidak akan membutuhkan semua 8 digit.
Stéphane Chazelas
@ StéphaneChazelas Menarik, saya selalu mengira bahwa POSIX akan sesuai dengan yang delapan digit. Saya menganggap versi delapan digit masih berlaku di zsh jika Anda ingin menghindari mengambil huruf dan angka tambahan setelah kode?
Draconis
Ya, \uxxxxadalah sampai dengan 4 digit dan \Uxxxxxxxxmerupakan sampai 8 digit. Perhatikan bahwa Unicode sekarang terbatas pada titik kode 0 hingga 0x10FFFF (batasan yang dibawa oleh UTF16) sehingga titik kode tidak akan pernah memiliki lebih dari 6 digit (masih \U123456789akan ditafsirkan sebagai karakter titik kode 0x12345678 diikuti oleh 9dan gagal). Spesifikasi POSIX untuk $'\u\U'masih belum selesai (lihat austingroupbugs.net/view.php?id=249 ). Dalam draft sebelumnya, mereka membutuhkan semua 4/8 digit tetapi itu berubah kemudian (atas permintaan saya).
Stéphane Chazelas