UTF-16 เป็นความกว้างคงที่หรือความกว้างผันแปรหรือไม่? ทำไม UTF-8 ถึงไม่มีปัญหาการสั่งซื้อแบบไบต์


16
  1. UTF-16 เป็นความกว้างคงที่หรือความกว้างผันแปรหรือไม่? ฉันได้รับผลลัพธ์ที่แตกต่างจากแหล่งข้อมูลอื่น:

    จากhttp://www.tbray.org/ongoing/When/200x/2003/04/26/UTF :

    UTF-16 เก็บอักขระ Unicode ในช่องสิบหกบิต

    จากhttp://en.wikipedia.org/wiki/UTF-16/UCS-2 :

    UTF-16 (รูปแบบการแปลง Unicode แบบ 16 บิต) เป็นการเข้ารหัสอักขระสำหรับ Unicode ที่สามารถเข้ารหัสได้ 1,112,064 หมายเลข [1] (เรียกว่าจุดโค้ด) ในพื้นที่โค้ด Unicode ตั้งแต่ 0 ถึง 0x10FFFF มันสร้างผลลัพธ์ความยาวผันแปรของหน่วยรหัส 16 บิตหนึ่งหรือสองหน่วยต่อจุดรหัส

  2. จากแหล่งแรก

    UTF-8 ยังมีข้อได้เปรียบที่หน่วยการเข้ารหัสเป็นไบต์ดังนั้นจึงไม่มีปัญหาการเรียงลำดับไบต์

    ทำไม UTF-8 ถึงไม่มีปัญหาการสั่งซื้อแบบไบต์ มันเป็นความกว้างผันแปรและตัวละครหนึ่งตัวอาจมีมากกว่าหนึ่งไบต์ดังนั้นฉันคิดว่าคำสั่งแบบไบต์อาจเป็นปัญหาได้หรือไม่

ขอบคุณและขอแสดงความนับถือ!


คำตอบ:


13

(1) ลำดับไบต์หมายความว่าอะไร arrary of char ใน C? UTF-16 เป็นลำดับไบต์หรือว่าเป็นอย่างไร (2) เหตุใดลำดับของไบต์จึงไม่เกี่ยวข้องกับความยาวของตัวแปร

คุณดูเหมือนจะเข้าใจผิดว่าประเด็น Endian คืออะไร นี่เป็นบทสรุปโดยย่อ

จำนวนเต็ม 32 บิตใช้เวลา 4 ไบต์ ตอนนี้เรารู้ลำดับตรรกะของไบต์เหล่านี้แล้ว หากคุณมีจำนวนเต็ม 32 บิตคุณจะได้รับไบต์สูงด้วยรหัสต่อไปนี้:

uint32_t value = 0x8100FF32;
uint8_t highByte = (uint8_t)((value >> 24) & 0xFF); //Now contains 0x81

นั่นคือทั้งหมดที่ดีและดี จุดเริ่มต้นของปัญหาคือฮาร์ดแวร์เก็บและเรียกข้อมูลจำนวนเต็มจากหน่วยความจำได้อย่างไร

ตามลำดับ Big Endian หน่วยความจำ 4 ไบต์ที่คุณอ่านเป็นจำนวนเต็ม 32 บิตจะถูกอ่านด้วยไบต์แรกเป็นไบต์สูง:

[0][1][2][3]

ตามลำดับ Little Endian หน่วยความจำ 4 ไบต์ที่คุณอ่านเป็นจำนวนเต็ม 32 บิตจะถูกอ่านด้วยไบต์แรกเป็นไบต์ต่ำ :

[3][2][1][0]

หากคุณมีตัวชี้ไปยังตัวชี้ไปยังค่า 32 บิตคุณสามารถทำได้ดังนี้

uint32_t value = 0x8100FF32;
uint32_t *pValue = &value;
uint8_t *pHighByte = (uint8_t*)pValue;
uint8_t highByte = pHighByte[0]; //Now contains... ?

ตาม C / C ++ ผลลัพธ์ของสิ่งนี้ไม่ได้ถูกกำหนด อาจเป็น 0x81 หรืออาจเป็น 0x32 ในทางเทคนิคมันสามารถคืนสิ่งใดก็ได้ แต่สำหรับระบบจริงมันจะคืนค่าอย่างใดอย่างหนึ่ง

หากคุณมีตัวชี้ไปยังที่อยู่หน่วยความจำคุณสามารถอ่านที่อยู่นั้นเป็นค่า 32 บิต, 16 บิตหรือ 8 บิต บนเครื่อง endian ขนาดใหญ่ตัวชี้ชี้ไปที่ไบต์สูง บนเครื่อง endian เล็กน้อยตัวชี้จะชี้ไปที่ไบต์ต่ำ

โปรดทราบว่านี่คือทั้งหมดที่เกี่ยวกับการอ่านและการเขียนไปยัง / จากหน่วยความจำ มันไม่มีส่วนเกี่ยวข้องกับรหัส C / C ++ ภายใน รุ่นแรกของรหัสที่หนึ่งที่ C / C ++ ไม่ได้ประกาศเป็น undefined จะเสมอการทำงานที่จะได้รับไบต์สูง

ปัญหาคือเมื่อคุณเริ่มอ่านสตรีมไบต์ เช่นจากไฟล์

ค่า 16 บิตมีปัญหาเช่นเดียวกับค่า 32 บิต พวกเขามีเพียง 2 ไบต์แทนที่จะเป็น 4 ดังนั้นไฟล์อาจมีค่า 16- บิตที่เก็บไว้ในลำดับใหญ่หรือน้อย endian

UTF-16 ถูกกำหนดให้เป็นลำดับของค่า 16 บิต uint16_t[]อย่างมีประสิทธิภาพก็คือ หน่วยรหัสแต่ละหน่วยมีค่า 16 บิต ดังนั้นเพื่อที่จะโหลด UTF-16 ได้อย่างถูกต้องคุณจะต้องรู้ว่าข้อมูลของ endian คืออะไร

UTF-8 ถูกกำหนดให้เป็นลำดับของค่า 8 บิต uint8_t[]มันเป็น หน่วยรหัสแต่ละหน่วยมีขนาด 8 บิต: ไบต์เดียว

ตอนนี้ทั้ง UTF-16 และ UTF-8 อนุญาตให้มีหน่วยรหัสหลายหน่วย (ค่า 16 บิตหรือ 8 บิต) เพื่อรวมเข้าด้วยกันเพื่อสร้าง Unicode codepoint ("อักขระ" แต่นั่นไม่ใช่คำที่ถูกต้องมันเป็นการทำให้เข้าใจง่าย ) การสั่งซื้อหน่วยรหัสเหล่านี้ที่เป็นจุดโค้ดเป็น dictated โดย UTF-16 และ UTF-8 เข้ารหัส

เมื่อประมวลผล UTF-16 คุณอ่านค่า 16 บิตทำสิ่งที่จำเป็นต้องใช้ในการแปลง endian จากนั้นคุณตรวจสอบว่ามันเป็นคู่ตัวแทน; ถ้าเป็นเช่นนั้นคุณอ่านค่า 16 บิตอื่นรวมทั้งสองและจากนั้นคุณจะได้รับค่า codepoint Unicode

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

ดังนั้นจึงไม่มีปัญหา endian กับ UTF-8


10

คำตอบของ Jeremy Banks นั้นถูกต้องที่สุดเท่าที่จะทำได้ แต่ไม่ได้ระบุการสั่งซื้อแบบไบต์

เมื่อคุณใช้ UTF-16 ร่ายมนตร์ส่วนใหญ่จะถูกจัดเก็บโดยใช้คำสองไบต์ - แต่เมื่อคำนั้นถูกเก็บไว้ในดิสก์ไฟล์คุณใช้คำสั่งใดเพื่อจัดเก็บไบต์ส่วนประกอบ

ตัวอย่างเช่นสัญลักษณ์ CJK (จีน) สำหรับคำว่า "น้ำ" มีการเข้ารหัส UTF-16 ในเลขฐานสิบหกที่ 6C34 เมื่อคุณเขียนว่าเป็นสองไบต์ลงดิสก์คุณเขียนมันเป็น "big-endian" (สองไบต์คือ 6C 34)? หรือคุณเขียนมันเป็น "little-endian (สองไบต์คือ 34 6C)?

ด้วย UTF-16 การเรียงลำดับทั้งสองนั้นถูกต้องและคุณมักจะระบุว่าไฟล์ใดมีโดยสร้างคำแรกในไฟล์เป็น Byte Order Mark (BOM) ซึ่งสำหรับการเข้ารหัสแบบ big-endian คือ FE FF และสำหรับ end-little การเข้ารหัสคือ FF FE

UTF-32 มีปัญหาเดียวกันและวิธีแก้ไขปัญหาเดียวกัน

UTF-8 ไม่มีปัญหานี้เพราะความยาวแปรผันและคุณเขียนลำดับไบต์ของ glyph ได้อย่างมีประสิทธิภาพราวกับว่ามันเป็น endian น้อย ตัวอย่างเช่นตัวอักษร "P" จะถูกเข้ารหัสเสมอโดยใช้หนึ่งไบต์ - 80 - และอักขระการแทนที่จะถูกเข้ารหัสเสมอโดยใช้สองไบต์ FF FD ในลำดับนั้น

บางโปรแกรมใส่ตัวบ่งชี้สามไบต์ (EF BB BF) ที่จุดเริ่มต้นของไฟล์ UTF-8 และที่ช่วยแยกความแตกต่าง UTF-8 จากการเข้ารหัสที่คล้ายกันเช่น ASCII แต่มันไม่ธรรมดายกเว้น MS Windows


ขอบคุณ! (1) ตัวอักษร "P" เป็นเพียงหนึ่งไบต์ใน UTF-8 ทำไมอักขระการแทนที่ถูกเพิ่มเข้ากับโค้ด (2) ใน UTF-8 มีอักขระอื่น ๆ ที่มีมากกว่าหนึ่งไบต์ใน UTF-8 เหตุใดไบต์สั่งระหว่างไบต์สำหรับอักขระแต่ละตัวจึงไม่มีปัญหา
StackExchange สำหรับ All

@Tim: (1) คุณไม่ต้องเพิ่มอักขระแทนลงในรหัสสำหรับ P หากคุณเห็น 80 FF FD นั่นคืออักขระสองตัวคืออักขระ P และอักขระทดแทน
Bob Murphy

(2) คุณเขียนและอ่านสองไบต์เสมอสำหรับ "อักขระแทน" เป็น FF FD ตามลำดับ จะมีปัญหาในการสั่งซื้อแบบไบต์เท่านั้นหากคุณสามารถเขียน "การแทนที่อักขระ" เป็น FD FF - แต่คุณไม่สามารถ; ลำดับของสองไบต์นั้นจะเป็นอย่างอื่นที่ไม่ใช่ "อักขระการแทนที่"
Bob Murphy

1
@ Tim: คุณอาจต้องการที่จะทำงานที่ผ่านen.wikipedia.org/wiki/UTF-8 มันค่อนข้างดีจริงๆและถ้าคุณสามารถเข้าใจได้ทั้งหมดและหน้า Wikipedia ที่เกี่ยวข้องกับ Unicode อื่น ๆ ฉันคิดว่าคุณจะพบว่าคุณไม่มีคำถามเพิ่มเติมอีกแล้ว
Bob Murphy

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