วิธีการแปลงอิโมติคอนที่ระบุโดยรหัส U + xxxxx เป็น utf-8


16

อิโมติคอนดูเหมือนจะถูกระบุโดยใช้รูปแบบของ U + xxxxx
โดยที่แต่ละ x เป็นเลขฐานสิบหก

ตัวอย่างเช่นU + 1F615เป็นรหัส Unicode Consortium อย่างเป็นทางการสำหรับ "สับสนใบหน้า" 😕

เมื่อฉันสับสนบ่อยฉันมีความสัมพันธ์ที่ดีต่อสัญลักษณ์นี้

การแทนU + 1F615ทำให้ฉันสับสนเพราะฉันคิดว่าการเข้ารหัสที่เป็นไปได้สำหรับอักขระ Unicode ต้องใช้ 8, 16, 24 หรือ 32 บิตในขณะที่ 5 หลักเลขฐานสิบต้องมี 5x4 = 20 บิต

ฉันได้ค้นพบว่าสัญลักษณ์นี้น่าจะเป็นสตริงเลขฐานสิบหกที่แตกต่างกันโดยสิ้นเชิงใน bash:

$echo -n 😕 | hexdump
0000000 f0 9f 98 95                                    
0000004

$echo -e "\xf0\x9f\x98\x95"
😕

$PS1=$'\xf0\x9f\x98\x95  >'
😕  >

ผมคาดว่าจะมีU + 1F615การแปลงเพื่อสิ่งที่ต้องการ\ x00 \ x01 \ xF6 \

ฉันไม่เห็นความสัมพันธ์ระหว่างการเข้ารหัสทั้งสองนี้หรือไม่

เมื่อฉันค้นหาสัญลักษณ์ในรายการUnicode Consortium อย่างเป็นทางการฉันต้องการใช้รหัสนั้นโดยตรงโดยไม่ต้องแปลงด้วยตนเองในแบบที่น่าเบื่อนี้ กล่าวคือ

  • การค้นหาสัญลักษณ์บนหน้าเว็บบางหน้า
  • คัดลอกไปยังคลิปบอร์ดของเว็บเบราว์เซอร์
  • วางใน bash เพื่อสะท้อนผ่าน hexdump เพื่อค้นหารหัส REAL

ฉันสามารถใช้รหัส 20 บิตนี้เพื่อกำหนดรหัส 32 บิตได้ไหม

มีความสัมพันธ์ระหว่างตัวเลขทั้งสองนี้หรือไม่?

คำตอบ:


20

UTF-8คือการเข้ารหัสความยาวผันแปรของ Unicode มันถูกออกแบบมาให้เป็นชุดของ ASCII ดูWikipediaสำหรับรายละเอียดของการเข้ารหัส \x00 \x01 \xF6 \x15จะเป็นUCS-4BEหรือUTF-32BEเข้ารหัส

ในการรับจากรหัส Unicode ชี้ไปที่การเข้ารหัส UTF-8 โดยสมมติว่า charmap ของโลแคลคือ UTF-8 (ดูผลลัพธ์ของlocale charmap) มันเป็นเพียง:

$ printf '\U1F615\n'
😕
$ echo -e '\U1F615'
😕
$ confused_face=$'\U1F615'

หลังจะอยู่ในเวอร์ชันถัดไปของมาตรฐาน POSIXจะอยู่ในรุ่นถัดไปของมาตรฐาน

AFAIK ไวยากรณ์ที่ถูกนำมาใช้ในปี 2000 โดยแบบสแตนด์อโลน GNU printfยูทิลิตี้ (เมื่อเทียบกับprintfยูทิลิตี้ของ GNU เปลือก) นำไปecho/ printf/ $'...'builtins แรกโดยzshในปี 2003 , ksh93 ในปี 2004 ทุบตีในปี 2010 ( แต่ทำงานไม่ถูกต้องมี จนถึงปี 2014 ) แต่ได้รับแรงบันดาลใจจากภาษาอื่นอย่างเห็นได้ชัด

ksh93นอกจากนี้ยังสนับสนุนเป็นและprintf '\x1f615\n'printf '\u{1f615}\n'

$'\uXXXX'และ$'\UXXXXXXXX'ได้รับการสนับสนุนโดยzsh, bash, ksh93, mkshและ FreeBSD sh, GNU แอฟริกาprintfecho

บางคนต้องการตัวเลขทั้งหมด (ซึ่ง\U0001F615ตรงข้ามกับ\U1F615) แม้ว่าอาจมีการเปลี่ยนแปลงในรุ่นอนาคตเนื่องจาก POSIX จะอนุญาตให้ตัวเลขน้อยลง ในกรณีใด ๆ คุณต้องมีตัวเลขทั้งหมดหาก\UXXXXXXXXจะต้องตามด้วยเลขฐานสิบหกเช่นเดียวกับใน\U0001F615FOXตามที่\U1F615FOXจะได้รับ$'\U001F615F'OXจะได้รับ

บางตัวขยายไปยังอักขระในการเข้ารหัสของโลแคลปัจจุบัน ณ เวลาที่สตริงถูกวิเคราะห์คำหรือ ณ เวลาที่ขยายตัวบางตัวใน UTF-8 โดยไม่คำนึงถึงโลแคล หากอักขระไม่พร้อมใช้งานในการเข้ารหัสของโลแคลปัจจุบันลักษณะการทำงานจะแตกต่างกันระหว่างเชลล์

ดังนั้นเพื่อการพกพาที่ดีที่สุดสิ่งที่ดีที่สุดคือใช้เฉพาะในโลแคล UTF-8 และใช้ตัวเลขทั้งหมดและใช้ใน$'...':

printf '%s\n' $'\U0001F615'

โปรดทราบว่า:

LC_ALL=C.UTF-8; printf '%s\n' $'\U0001F615'

หรือ:

{
  LC_ALL=C.UTF-8
  printf '%s\n' $'\U0001F615'
}

จะไม่ทำงานกับเชลล์ทั้งหมด (รวมถึงbash) เพราะ$'\U0001F615'ถูกวิเคราะห์คำก่อนLC_ALLกำหนด (โปรดทราบว่าไม่มีการรับประกันว่าระบบจะมีโลแคลที่เรียกว่าC.UTF-8)

คุณต้องการ:

LC_ALL=C.UTF-8; eval "confused_face=$'\U0001F615'"

หรือ:

LC_ALL=C.UTF-8
printf '%s\n' $'\U0001F615'

(ไม่อยู่ในคำสั่งผสมหรือฟังก์ชั่น)


สำหรับย้อนกลับจะได้รับจากการเข้ารหัส UTF-8 กับ Unicode รหัสจุดเห็นนี้คำถามอื่น ๆหรือที่หนึ่ง

$ unicode 😕 
U+1F615 CONFUSED FACE
UTF-8: f0 9f 98 95  UTF-16BE: d83dde15  Decimal: 😕
😕
Category: So (Symbol, Other)
Bidi: ON (Other Neutrals)

$ perl -CA -le 'printf "%x\n", ord shift' 😕
1f615

2
ขอให้สังเกตว่าถ้า\U1F615ตามด้วยเลขฐานสิบหกหลักที่ถูกต้องแล้วจะถือว่าเป็นส่วนหนึ่งของลำดับการหลบหนี เพื่อให้มันทำงานโดยไม่คำนึงถึงสิ่งที่ตามมามันจะต้องมีศูนย์นำหน้ามากพอที่จะมีความยาวแปดหลักอย่างแน่นอน\U0001F615
kasperd

@kasperd ขอบคุณ ใช่มันเป็นที่น่าสังเกต ฉันได้รวมไว้ในคำตอบ
Stéphane Chazelas

7

นี่เป็นวิธีการแปลงจาก UTF-32 (big endian) เป็น UTF-8

$ confused=$(echo -ne "\x0\x01\xF6\x15" | iconv -f UTF-32BE -t UTF-8)     
$ echo $confused 
😕

คุณจะสังเกตเห็นค่าเลขฐานสิบหกของคุณ0x01F615พร้อมกับ 0 นำหน้าพิเศษเพื่อเติม 32 บิต

หน้า Wikipedia บนUTF-8อธิบายการแปลงจาก Unicode codepoint เป็น UTF-8 ที่เป็นตัวแทนอย่างชัดเจน แต่การพยายามทำด้วยตัวเองในการเขียนสคริปต์เปลือกอาจไม่ใช่ความคิดที่ดีที่สุด

UTF-32มีความกว้างคงที่และการติดต่อระหว่าง codepoint และการเป็นตัวแทน UTF-32 นั้นเล็กน้อย - ค่าเหมือนกัน


6

วิธีที่ดีที่จะทำในหัวของคุณหรือบนกระดาษ:

  1. ลองคิดดูว่าจะมีกี่ไบต์: ค่าภายใต้ U + 0080 คือหนึ่งไบต์ส่วนอื่นที่อยู่ใต้ U + 0800 จะเป็น 2 ไบต์ส่วนอื่น ๆ ภายใต้ U + 10000 จะเป็น 3 ไบต์และอีก 4 ไบต์ ในกรณีของคุณ 4 ไบต์

  2. แปลง hex เป็นฐานแปด: 0373025.

  3. เริ่มต้นที่ท้ายที่สุดแล้วลอกออก 2 037 030 025หลักฐานแปดในเวลาที่จะได้รับลำดับของค่าฐานแปด:

  4. ถ้าคุณมีค่าฐานแปดน้อยกว่าจำนวนที่คาดหวังของไบต์เพิ่มพิเศษ 0 000 037 030 025ที่จุดเริ่มต้น:

  5. สำหรับทั้งหมดยกเว้นคนแรกให้เพิ่ม0200เพื่อรับ: 000 0237 0230 0225.

  6. สำหรับครั้งแรกเพิ่ม0300หากความยาวที่คาดว่าจะเป็น 2, 0340ถ้ามัน 3 หรือ0360ถ้าเป็นที่ 4 360 0237 0230 0225ที่จะได้รับ:

ตอนนี้เขียนเป็นสตริงของการแปดฐานหนี: \360\237\230\225. เลือกแปลงกลับเป็น hex หากคุณต้องการ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.