UTF-8 สามารถเข้ารหัสอักขระได้กี่ตัว?


105

ถ้า UTF-8 เป็น 8 บิตไม่ได้หมายความว่าจะมีอักขระที่แตกต่างกันได้สูงสุด 256 ตัวหรือไม่?

จุดรหัส 128 รายการแรกเหมือนกับใน ASCII แต่มันบอกว่า UTF-8 สามารถรองรับได้ถึงล้านตัวอักษร?

วิธีนี้ทำงานอย่างไร?


2
หากคุณสามารถประเมินคำถามนี้ใหม่ได้เนื่องจากคำตอบทั้งหมดไม่ถูกต้อง อ่านคำตอบของฉัน: stackoverflow.com/a/45042566/124486
Evan Carroll

ในการเข้ารหัส UTF-8, UTF-16, UTF-32 ของ Unicode จำนวนคือจำนวนบิตในหน่วยรหัสซึ่งหนึ่งหรือมากกว่านั้นเข้ารหัสจุดรหัส Unicode
Tom Blodget

1
ฉันตอบคำถามนี้เมื่อไม่นานมานี้ด้วยความพยายามที่จะทำให้ตรงขึ้นมันจะดีมากถ้าคุณจะชั่งน้ำหนักกับคำตอบที่เลือกซึ่งเป็นเพียงคำพูดเดียวของวิกิพีเดียที่ไม่ได้บอกเล่าเรื่องราวทั้งหมด ชัดเจนกว่ามาก)
Evan Carroll

คำตอบ:


139

UTF-8 ไม่ได้ใช้หนึ่งไบต์ตลอดเวลาคือ 1 ถึง 4 ไบต์

อักขระ 128 ตัวแรก (US-ASCII) ต้องมีหนึ่งไบต์

อักขระ 1,920 ตัวถัดไปต้องใช้สองไบต์ในการเข้ารหัส ซึ่งครอบคลุมส่วนที่เหลือของตัวอักษรละตินเกือบทั้งหมดและยังรวมถึงตัวอักษรกรีกซีริลลิกคอปติกอาร์เมเนียฮิบรูอารบิกซีรีแอกและทานารวมทั้งการรวมเครื่องหมายกำกับ

จำเป็นต้องใช้สามไบต์สำหรับอักขระในส่วนที่เหลือของเครื่องบินหลายภาษาขั้นพื้นฐานซึ่งมีอักขระแทบทั้งหมดที่ใช้กันทั่วไป [12] รวมทั้งอักขระภาษาจีนญี่ปุ่นและเกาหลี [CJK] ส่วนใหญ่

จำเป็นต้องใช้สี่ไบต์สำหรับอักขระในระนาบอื่น ๆ ของ Unicode ซึ่งรวมถึงอักขระ CJK ที่ใช้น้อยกว่าสคริปต์ประวัติศาสตร์ต่างๆสัญลักษณ์ทางคณิตศาสตร์และอีโมจิ (สัญลักษณ์รูปภาพ)

ที่มา: Wikipedia


สวัสดี @zwippie ฉันเพิ่งใหม่สำหรับสิ่งนี้ มีบางอย่างที่ฉันไม่เข้าใจ! BMP ใช้ 2 ไบต์ที่คุณบอกคือ 3? ฉันผิด?
chiperortiz

1
@chiperortiz, BMP เป็น 16 บิตดังนั้นจึงสามารถเข้ารหัสเป็น UTF-16 โดยมีความยาวคงที่ต่ออักขระ (UTF-16 รองรับการใช้งานมากกว่า 16 บิต แต่เป็นการปฏิบัติที่ยากและการใช้งานจำนวนมากไม่รองรับ) อย่างไรก็ตามสำหรับ UTF-8 คุณต้องเข้ารหัสด้วยว่าจะใช้เวลานานเท่าใดดังนั้นคุณจึงสูญเสียบิตไปบางส่วน นั่นคือเหตุผลที่คุณต้องใช้ 3 ไบต์เพื่อเข้ารหัส BMP ที่สมบูรณ์ สิ่งนี้อาจดูเหมือนสิ้นเปลือง แต่โปรดจำไว้ว่า UTF-16 ใช้ 2 ไบต์เสมอ แต่ UTF-8 ใช้หนึ่งไบต์ต่ออักขระสำหรับอักขระภาษาที่ใช้ภาษาละตินส่วนใหญ่ ทำให้มีขนาดกะทัดรัดเป็นสองเท่า
sanderd17

แรงผลักดันหลักของคำถามของ OP เกี่ยวข้องกับสาเหตุที่เรียกว่า UTF- 8ซึ่งไม่ได้ตอบโจทย์นั้นจริงๆ
jbyrd

@ sanderd17 ความแตกต่างระหว่าง utf8 และ 16 คือ utf-8 สามารถใช้ขั้นต่ำ 1 ไบต์ (เพียงพอสำหรับละติน) ในขณะที่ 16 ต้องการอย่างน้อย 2 ไบต์?
Timo

44

UTF-8 ใช้ 1-4 ไบต์ต่ออักขระ: หนึ่งไบต์สำหรับอักขระ ascii (ค่ายูนิโคด 128 ตัวแรกจะเหมือนกับ ascii) แต่ต้องใช้เพียง 7 บิต หากตั้งค่าบิต ("เครื่องหมาย") สูงสุดไว้แสดงว่าเริ่มต้นของลำดับแบบหลายไบต์ จำนวนชุดบิตสูงที่ต่อเนื่องกันแสดงจำนวนไบต์จากนั้นจึงเป็น 0 และบิตที่เหลือจะนำไปสู่ค่า สำหรับไบต์อื่นสองบิตสูงสุดจะเป็น 1 และ 0 และ 6 บิตที่เหลือเป็นค่า

ดังนั้นลำดับสี่ไบต์จะเริ่มต้นด้วย 11110 ... (และ ... = สามบิตสำหรับค่า) จากนั้นสามไบต์กับ 6 บิตต่อค่าโดยให้ค่า 21 บิต 2 ^ 21 เกินจำนวนอักขระ Unicode ดังนั้นจึงสามารถแสดง Unicode ทั้งหมดเป็น UTF8 ได้


@ นิกแอล. ไม่ฉันหมายถึง 3 ไบต์ ในตัวอย่างนั้นหากไบต์แรกของลำดับหลายไบต์เริ่มต้น 1111 1 ตัวแรกบ่งชี้ว่าเป็นจุดเริ่มต้นของลำดับหลายไบต์จากนั้นจำนวน 1 ที่ต่อเนื่องกันหลังจากนั้นจะระบุจำนวนไบต์เพิ่มเติมในลำดับ (ดังนั้นตัวแรก ไบต์จะขึ้นต้น 110, 1110 หรือ 11110)
CodeClown42

พบหลักฐานสำหรับคำพูดของคุณใน RFC 3629. tools.ietf.org/html/rfc3629#section-3 อย่างไรก็ตามฉันไม่เข้าใจว่าทำไมฉันต้องวาง "10" ไว้ที่จุดเริ่มต้นของไบต์ที่สอง 110xxxxx 10xxxxxx ทำไมไม่แค่ 110xxxxx xxxxxxxx?
kolobok

3
พบคำตอบในsoftwareengineering.stackexchange.com/questions/262227/… . เพียงเพื่อความปลอดภัย (ในกรณีที่ไบต์เดียวกลางสตรีมเสียหาย)
kolobok

@kolobok อ่า. Sans ปลอดภัยจากนั้นคุณสามารถเข้ารหัสค่า 21 บิตเป็น 3 ไบต์ (3 บิตแสดงความยาวบวก 21 บิต) : D อาจจะไม่ค่อยมีความหมายนัก แต่อย่างน้อย WRT ภาษาตะวันตก
CodeClown42

ฉันเดาว่า NickL ถามสิ่งนี้ แต่เกิดอะไรขึ้นกับส่วนที่เหลือของบิตในไบต์แรกนั้นถ้า ... แทนไบต์ที่ตามมาแทนที่จะเป็นบิต?
c6754

27

ตามตารางนี้ * UTF-8 ควรรองรับ:

2 31 = 2,147,483,648 อักขระ

อย่างไรก็ตาม RFC 3629 จำกัด ค่าที่เป็นไปได้ดังนั้นตอนนี้เราถูกจำกัด ไว้ที่ 4 ไบต์ซึ่งให้เรา

2 21 = 2,097,152 อักขระ

โปรดทราบว่าอักขระเหล่านี้ส่วนใหญ่ "สงวนไว้" สำหรับการใช้งานแบบกำหนดเองซึ่งจริงๆแล้วค่อนข้างสะดวกสำหรับไอคอนฟอนต์

* ใช้ Wikipedia แสดงตารางที่มีขนาด 6 ไบต์ - นับตั้งแต่อัปเดตบทความ

2017-07-11:แก้ไขสำหรับการนับจุดรหัสเดียวกันสองครั้งที่เข้ารหัสด้วยหลายไบต์


คำตอบนี้คือการนับจำนวนการเข้ารหัสที่เป็นไปได้สองเท่า เมื่อคุณนับ 2 ^ 7 ทั้งหมดแล้วคุณจะไม่สามารถนับได้อีกใน 2 ^ 11, 2 ^ 16 เป็นต้นจำนวนการเข้ารหัสที่ถูกต้องที่เป็นไปได้คือ 2 ^ 21 (แม้ว่าจะยังไม่ได้ใช้ทั้งหมด)
Jimmy

@ จิมมี่คุณแน่ใจว่าฉันนับสองครั้ง? 0xxxxxxxให้ 7 บิตที่ใช้งานได้110xxxxx 10xxxxxxให้อีก 11 - ไม่มีการทับซ้อนกัน ไบต์แรกเริ่มต้นด้วย0ในกรณีแรกและ1ในกรณีที่สอง
mpen

@mpen แล้ว code point 00000001เก็บอะไรและ11000000 100000001เก็บอะไร?
Evan Carroll

1
@EvanCarroll เอ่อ .... จุดที่ถ่าย. ไม่ทราบว่ามีหลายวิธีในการเข้ารหัสจุดรหัสเดียวกัน
mpen

1
ฉันพยายามจะตอบคำถามนี้ด้วยตัวเองดูว่าคุณคิดว่านี่เป็นคำอธิบายที่ดีกว่าและตอบคำถามได้หรือไม่: stackoverflow.com/a/45042566/124486
Evan Carroll

24

Unicode เทียบกับ UTF-8

Unicode แก้ไขจุดรหัสเป็นอักขระ UTF-8 เป็นกลไกการจัดเก็บสำหรับ Unicode Unicode มีข้อมูลจำเพาะ UTF-8 มีข้อมูลจำเพาะ พวกเขาทั้งสองมีขีด จำกัด ที่แตกต่างกัน UTF-8 มีขอบเขตขึ้นที่แตกต่างกัน

Unicode

Unicode กำหนดด้วย"เครื่องบิน" เครื่องบินแต่ละลำมีรหัส16จุด2 จุด มี 17 เครื่องบินใน Unicode สำหรับ17 * 2^16จุดรหัสทั้งหมด เครื่องบินลำแรกที่เครื่องบิน 0 หรือ BMPเป็นพิเศษในน้ำหนักของสิ่งที่จะได้ดำเนินการ

แทนที่จะอธิบายความแตกต่างทั้งหมดให้ฉันอ้างบทความข้างต้นเกี่ยวกับเครื่องบิน

เครื่องบิน 17 ลำรองรับได้ 1,114,112 จุดรหัส ในจำนวนนี้ 2,048 คนเป็นตัวแทนโดย 66 เป็นอักขระที่ไม่ใช่อักขระและ 137,468 ถูกสงวนไว้สำหรับการใช้งานส่วนตัวโดยปล่อยให้ 974,530 คนสำหรับการมอบหมายงานสาธารณะ

UTF-8

ตอนนี้กลับไปที่บทความที่ลิงก์ด้านบน

รูปแบบการเข้ารหัสที่ใช้โดย UTF-8 ได้รับการออกแบบโดยมีขีด จำกัด ที่ใหญ่กว่ามากคือ 2 31จุดรหัส (เครื่องบิน 32,768) และสามารถเข้ารหัส 2 21จุดรหัส (32 ระนาบ) แม้ว่าจะ จำกัด ไว้ที่ 4 ไบต์ก็ตาม เนื่องจาก Unicode จำกัด จุดรหัสไว้ที่เครื่องบิน 17 ลำที่สามารถเข้ารหัสโดย UTF-16 จุดรหัสที่สูงกว่า 0x10FFFF จึงไม่ถูกต้องใน UTF-8 และ UTF-32

คุณจะเห็นว่าคุณสามารถใส่สิ่งต่างๆลงใน UTF-8 ที่ไม่ใช่ Unicode ที่ถูกต้อง ทำไม? เนื่องจาก UTF-8 รองรับจุดรหัสที่ Unicode ไม่รองรับด้วยซ้ำ

UTF-8 แม้จะมีข้อ จำกัด สี่ไบต์ แต่ก็รองรับ 2 21รหัสพอยต์ซึ่งมากกว่า17 * 2^16


20

2,164,864“ อักขระ” สามารถเข้ารหัสได้โดย UTF-8

ตัวเลขนี้มาจากวิธีการทำงานของการเข้ารหัส:27 + 211 + 216 + 221

  • อักขระ 1 ไบต์มี 7 บิตสำหรับการเข้ารหัส 0xxxxxxx(0x00-0x7F)

  • อักขระ 2 ไบต์มี 11 บิตสำหรับการเข้ารหัส 110xxxxx 10xxxxxx(0xC0-0xDF สำหรับไบต์แรก 0x80-0xBF สำหรับวินาที)

  • อักขระ 3 ไบต์มี 16 บิตสำหรับการเข้ารหัส 1110xxxx 10xxxxxx 10xxxxxx(0xE0-0xEF สำหรับไบต์แรก 0x80-0xBF สำหรับไบต์ต่อเนื่อง)

  • อักขระ 4 ไบต์มี 21 บิตสำหรับการเข้ารหัส 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx(0xF0-0xF7 สำหรับไบต์แรก 0x80-0xBF สำหรับไบต์ต่อเนื่อง)

ดังที่คุณเห็นว่ามีขนาดใหญ่กว่า Unicode ปัจจุบันอย่างมาก (1,112,064 อักขระ)

อัปเดต

การคำนวณเริ่มต้นของฉันผิดพลาดเพราะไม่ได้พิจารณากฎเพิ่มเติม ดูความคิดเห็นของคำตอบนี้สำหรับรายละเอียดเพิ่มเติม


2
คณิตศาสตร์ของคุณไม่เคารพกฎ UTF-8 ที่อนุญาตให้เข้ารหัสเฉพาะจุดรหัสที่สั้นที่สุดเท่านั้น ดังนั้น 00000001 จึงใช้ได้สำหรับ U + 0001 แต่ 11110000 10000000 10000000 10000001 ไม่ใช่ อ้างถึงตารางที่ 3-7 รูปแบบที่ดี UTF-8 Byte ลำดับ นอกจากนี้ตารางจะตอบคำถามโดยตรง: คุณเพียงแค่เพิ่มช่วง (พวกเขาไม่ปะติดปะต่อเพื่อยกเว้นตัวแทนสำหรับ UTF-16)
Tom Blodget

ทอม - ขอบคุณสำหรับความคิดเห็นของคุณ! ฉันไม่รู้ถึงข้อ จำกัด เหล่านั้น ฉันเห็นตาราง 3-7และเรียกใช้ตัวเลขและดูเหมือนว่ามีลำดับที่ถูกต้อง 1,083,392 ลำดับ
Ruben Reyes

นี่คือคำตอบที่ถูกต้อง คำตอบอื่น ๆ หยุดอยู่เพียงแค่นั้น2^21และลืมชุดค่าผสมที่เหลือที่เป็นไปได้
Manu Manjunath

6

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


2
นี่เป็นความเข้าใจผิด จุดรหัสที่ยาวที่สุดที่คุณสามารถมีได้คือ11110xxx 10xxxxxx 10xxxxxx 10xxxxxxดังนั้นจึงสามารถใช้เพียง 21 บิตในการเข้ารหัสอักขระจริง
Boris

6
ฉันบอกว่าจุดรหัสอาจใช้เวลาถึง 32 บิตในการเข้ารหัสฉันไม่เคยอ้างว่า (โดยการเหนี่ยวนำ) คุณสามารถเข้ารหัสอักขระ 2 ^ 32 ใน 32 บิต UTF-8 แต่นั่นค่อนข้างน่าเบื่อเนื่องจากคุณสามารถเข้ารหัสอักขระ Unicode ที่มีอยู่ทั้งหมดใน UTF-8 และคุณสามารถเข้ารหัสได้มากขึ้นหากคุณยืด UTF-8 เป็น 48 บิต (ซึ่งมีอยู่ แต่เลิกใช้แล้ว) ดังนั้นฉันไม่แน่ใจว่าอะไร จุดที่ทำให้เข้าใจผิดคือ
หลอกลวง

4

คำพูดจาก Wikipedia: "UTF-8 เข้ารหัสแต่ละจุดรหัส 1,112,064 จุดในชุดอักขระ Unicode โดยใช้ไบต์ 8 บิตหนึ่งถึงสี่ตัว (เรียกว่า" อ็อกเต็ต "ใน Unicode Standard)"

ลิงค์บางส่วน:


1

ตรวจสอบมาตรฐาน Unicode และข้อมูลที่เกี่ยวข้องเช่นพวกเขารายการคำถามที่พบบ่อยUTF-8 UTF-16 UTF-32 & BOM ไม่ใช่การแล่นเรือที่ราบรื่น แต่เป็นข้อมูลที่เชื่อถือได้และสิ่งที่คุณอาจอ่านเกี่ยวกับ UTF-8 ที่อื่นเป็นเรื่องที่น่าสงสัย

“ 8” ใน“ UTF-8” เกี่ยวข้องกับความยาวของหน่วยรหัสเป็นบิต หน่วยรหัสคือเอนทิตีที่ใช้ในการเข้ารหัสอักขระไม่จำเป็นต้องเป็นการแมปแบบตัวต่อตัวแบบธรรมดา UTF-8 ใช้จำนวนหน่วยรหัสที่แปรผันเพื่อเข้ารหัสอักขระ

คอลเลกชันของอักขระที่สามารถเข้ารหัสใน UTF-8 นั้นเหมือนกับ UTF-16 หรือ UTF-32 นั่นคืออักขระ Unicode ทั้งหมด พวกเขาทั้งหมดเข้ารหัสพื้นที่การเข้ารหัส Unicode ทั้งหมดซึ่งรวมถึง noncharacters และจุดรหัสที่ไม่ได้กำหนด


0

แม้ว่าฉันจะเห็นด้วยกับ mpen เกี่ยวกับรหัส UTF-8 สูงสุดในปัจจุบัน (2,164,864) (ตามรายการด้านล่างฉันไม่สามารถแสดงความคิดเห็นเกี่ยวกับเขาได้) เขาจะปิด 2 ระดับหากคุณลบข้อ จำกัด หลัก 2 ข้อของ UTF-8: เพียง 4 ไบต์ ไม่สามารถใช้ขีด จำกัด และรหัส 254 และ 255 ได้ (เขาลบขีด จำกัด 4 ไบต์เท่านั้น)

รหัสเริ่มต้น 254 เป็นไปตามการจัดเรียงพื้นฐานของบิตเริ่มต้น (ตั้งค่าสถานะหลายบิตเป็น 1 จำนวน 6 1 และเทอร์มินัล 0 ไม่มีบิตสำรอง) ให้ 6 ไบต์เพิ่มเติมในการทำงานกับ (6 10xxxxxx กลุ่มเพิ่มเติม 2 ^ 36 รหัส)

รหัสเริ่มต้น 255 ไม่ตรงตามการตั้งค่าพื้นฐานไม่มีเทอร์มินัล 0 แต่ใช้บิตทั้งหมดทำให้คุณมีไบต์เพิ่มเติมอีก 7 ไบต์ (ตั้งค่าสถานะแบบหลายบิตเป็น 1 จำนวน 7 1 และไม่มีเทอร์มินัล 0 เนื่องจากใช้บิตทั้งหมด ; 7 กลุ่ม 10xxxxxx รหัสเพิ่มเติม 2 ^ 42)

การเพิ่มสิ่งเหล่านี้ในชุดอักขระที่นำเสนอได้สูงสุดสุดท้ายคือ 4,468,982,745,216 นี่เป็นมากกว่าอักขระทั้งหมดในการใช้งานปัจจุบันภาษาเก่าหรือภาษาที่ตายแล้วและภาษาที่หลงเชื่อใด ๆ Angelic หรือ Celestial script ใคร?

นอกจากนี้ยังมีรหัสไบต์เดี่ยวที่ถูกมองข้าม / ละเว้นในมาตรฐาน UTF-8 นอกเหนือจาก 254 และ 255: 128-191 และอื่น ๆ อีกเล็กน้อย แป้นพิมพ์บางตัวใช้ในเครื่องตัวอย่างเช่นรหัส 128 มักจะเป็นการลบ backspace รหัสเริ่มต้นอื่น ๆ (และช่วงที่เกี่ยวข้อง) ไม่ถูกต้องด้วยเหตุผลอย่างน้อยหนึ่งข้อ ( https://en.wikipedia.org/wiki/UTF-8#Invalid_byte_sequences )


-1

Unicode แต่งงานกับ UTF-8 อย่างมั่นคง Unicode รองรับโค้ดพอยต์ 2 ^ 21 โดยเฉพาะ (2,097,152 อักขระ) ซึ่งเป็นจำนวนจุดโค้ดที่รองรับโดย UTF-8 ทั้งสองระบบสงวนพื้นที่ 'ตาย' เท่ากันและโซนที่ จำกัด สำหรับจุดรหัสเป็นต้น... ณ เดือนมิถุนายน 2018 Unicode 11.0 เวอร์ชันล่าสุดมีตัวละคร 137,439 ตัว

จากมาตรฐานยูนิโคด. คำถามที่พบบ่อยเกี่ยวกับ Unicode

Unicode Standard เข้ารหัสอักขระในช่วง U + 0000..U + 10FFFF ซึ่งเท่ากับพื้นที่โค้ด 21 บิต

จากหน้า UTF-8 Wikipedia คำอธิบาย UTF-8

เนื่องจากข้อ จำกัด ของ Unicode code-space เป็นค่า 21 บิตในปี 2003 UTF-8 จึงถูกกำหนดให้เข้ารหัสจุดรหัสในหนึ่งถึงสี่ไบต์ ...


มีการปัดเศษ 21 บิตขึ้น Unicode รองรับ 1,114,112 codepoints (U + 0000 ถึง U + 10FFFF) อย่างที่บอก (บางครั้งอธิบายว่าเป็นเครื่องบิน 17 ลำของ 65536)
Tom Blodget

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