เหตุใดอักขระ Unicode บางตัวจึงไม่พิมพ์ไปยังเทอร์มินัลของฉัน


16

ฉันกำลังเรียกใช้ Arch Linux ด้วยเทอร์มินัลอย่างง่ายโดยใช้แบบอักษร Adobe Source Code Pro LANG=en_US.UTF-8สถานที่เกิดเหตุของฉันเป็นที่ตั้งอย่างถูกต้อง

ฉันต้องการพิมพ์อักขระ Unicode ที่เป็นตัวแทนการเล่นไพ่ไปยังเทอร์มินัลของฉัน ฉันใช้วิกิพีเดียสำหรับการอ้างอิง

อักขระ Unicode สำหรับการ์ดทำงานได้ดี ตัวอย่างเช่นการออก

$ printf "\u2660"

พิมพ์หัวใจสีดำไปที่หน้าจอ

อย่างไรก็ตามฉันมีปัญหากับการเล่นไพ่โดยเฉพาะ ออก

$ printf "\u1F0A1"

พิมพ์สัญลักษณ์Ἂ1แทนเอซโพดำ🂡 เกิดอะไรขึ้น

ปัญหานี้ยังคงมีอยู่ในหลายเทอร์มินัล (urxvt, xterm, ปลวก) และตัวอักษรทุกตัวที่ฉันได้ลอง (DejaVu, Inconsolata)


คำเตือน: ถ้าสิ่งนี้ถูกจัดการโดย printf มันเป็นการปรับปรุงที่ไม่ได้มาตรฐาน ดังนั้นอย่าคาดหวังว่าการหลบหนีเช่นนี้จะทำงานได้เลย ดู: pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html
schily

คำตอบ:


27

help printfdefers printf(1)สำหรับตีความลำดับ escape และdocs สำหรับ GNU printfพูดว่า:

printfตีความไวยากรณ์แบบตัวอักษรที่นำมาใช้ในการรับรองมาตรฐาน ISO C 99: \uสำหรับ Unicode (ISO / IEC 10646) ตัวอักษร 16 บิตระบุเป็นตัวเลขสี่หลักเลขฐานสิบหกhhhhและ\Uสำหรับ 32-bit ตัวอักษร Unicode ระบุเป็นตัวเลขแปดเลขฐานสิบหกhhhhhhhh printfเอาต์พุตอักขระ Unicode ตามLC_CTYPEโลแคล อักขระ Unicode ในช่วง U + 0000 … U + 009F, U + D800 … U + DFFF ไม่สามารถระบุได้ด้วยไวยากรณ์นี้ยกเว้น U + 0024 ($), U + 0040 (@), และ U + 0060 (`) .

มีการระบุบางสิ่งที่คล้ายคลึงกันในคู่มือ Bash สำหรับANSI C Quotingและecho:

\uHHHH
อักขระ Unicode (ISO / IEC 10646) ที่มีค่าเป็นค่าเลขฐานสิบหกHHHH (หนึ่งถึงสี่หลักสิบหกหลัก)

\UHHHHHHHH
อักขระ Unicode (ISO / IEC 10646) ที่มีค่าเป็นค่าเลขฐานสิบหกHHHHHHHHH (หนึ่งถึงแปดหลักแปด)

ในระยะสั้น: \uไม่ใช่สำหรับเลขฐานสิบหก 5 หลัก มันคือ\U:

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

2

คำตอบของ Muru นั้นถูกต้องสมบูรณ์ แต่เพียงเพื่อชี้แจงจุดหนึ่ง:

เมื่อคุณกำลังพิมพ์\u1F0A1นั่นแปลว่า Unicode แบบสิบหกบิต\u1F0Aตามด้วยตัวอักษรที่แท้จริง1(เนื่องจาก\uใช้อักขระสี่ตัวต่อไปนี้ไม่มากไม่น้อยไปกว่านี้) จากนั้น U + 1F0A จะให้อัลฟ่ากรีกพร้อมกำกับออกเสียงคู่หนึ่ง ( กรีกตัวพิมพ์ใหญ่ตัวอักษรอัลฟ่ากับ Psili และ Variaเพื่อความแม่นยำ)

หากคุณต้องการมากกว่าสิบหกบิตในการหลบหนี Unicode ของคุณคุณจำเป็นต้องใช้\Uซึ่งใช้เวลาถึงค่าฐานสิบหกของอักขระแปดตัว: \U0001F0A1จะให้ไพ่แก่คุณ


\U0001F0A1\U1F0A1เป็นจริงแบบพกพามากกว่า มันเป็นแบบสแตนด์อโลน GNU printfยูทิลิตี้ซึ่งเป็นครั้งแรกแนะนำเหล่านั้น\uXXXX/ \UXXXXXXXXลำดับและมันไม่จำเป็นต้องมี 4 หลักสำหรับ\uและ \U8 printfการใช้งานอื่น ๆเช่น builtin ของเชลล์ GNU, ksh93 และ zsh เป็นหละหลวมมากขึ้น ไม่ว่าในกรณีใด ๆprintf '\u/\U'POSIX POSIX กำลังจะระบุ zsh $'\U1F0A1'และจะไม่ต้องการตัวเลข 8 หลักทั้งหมด
Stéphane Chazelas

@ StéphaneChazelasที่น่าสนใจฉันมักจะคิดว่า POSIX จะไปกับแปดหลัก ฉันคิดว่ารุ่นแปดหลักยังคงใช้ได้ใน zsh หากคุณต้องการหลีกเลี่ยงการจับตัวอักษรและตัวเลขเพิ่มเติมหลังจากรหัส?
Draconis

ใช่\uxxxxเป็นขึ้นถึง 4 หลักและ\Uxxxxxxxxเป็นขึ้นถึง 8 หลัก โปรดทราบว่าขณะนี้ Unicode ถูก จำกัด ไว้ที่ codepoints 0 ถึง 0x10FFFF (ข้อ จำกัด ที่นำโดย UTF16) ดังนั้นจุดรหัสจะไม่เกิน 6 หลัก (ยังคง\U123456789ถูกตีความว่าเป็นตัวอักษรของจุดรหัส 0x12345678 ตามด้วย9และล้มเหลว) ข้อมูลจำเพาะ POSIX สำหรับ$'\u\U'ยังไม่สิ้นสุด (ดูaustingroupbugs.net/view.php?id=249 ) ในร่างก่อนหน้านี้พวกเขาต้องการตัวเลข 4/8 หลักทั้งหมด แต่เปลี่ยนแปลงในภายหลัง (ตามคำขอของฉัน)
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.