ความแตกต่างระหว่าง UTF-8 และ Unicode คืออะไร


503

ผมเคยได้ยินขัดแย้งความคิดเห็นจากคน - ตามที่วิกิพีเดีย UTF-8หน้า

พวกมันเหมือนกันใช่มั้ย บางคนสามารถอธิบายได้หรือไม่


1
สิ่งที่ WIKI นี้เขียนเกี่ยวกับยูนิโค้ดและ UTFs ก็โอเคในความคิดของฉัน ความคิดเห็นบางอย่างเกี่ยวกับมันแปลก: "มันเป็นไปได้ใน UTF-8 (หรือการเข้ารหัสหลายไบต์อื่น ๆ ) เพื่อแยกหรือตัดสตริงในกลางของตัวละครซึ่งอาจส่งผลให้สตริงที่ไม่ถูกต้อง" ดังนั้นสตริงที่ได้รับการเข้ารหัส UTF-8 จะไม่เป็นสตริงอีกต่อไป แต่เป็นไบต์อาร์เรย์หรือสตรีมไบต์ อักขระที่ประกอบเป็นสตริงจะถูกเข้ารหัส แน่นอนมันสามารถถอดรหัสได้เช่นกัน ตอนนี้แน่นอนคุณสามารถตัดลำดับ utf-8 หลังจากเริ่มต้นไบต์หรือหลังไบต์ต่อไปนี้ แต่ทำไมบางคนควรทำเช่นนี้?
bright

บทความเกี่ยวกับประเภทข้อมูลสตริงนี้เป็นเรื่องเกี่ยวกับการศึกษา: mortoray.com/2013/11/27/the-string-type-is-broken - บางครั้งเมื่อทำงานกับสตริงและส่วนประกอบระดับไบต์คุณอาจสับอักขระในครึ่งหนึ่งโดยไม่ตั้งใจ .
Everett

คำตอบ:


495

หากต้องการขยายคำตอบที่ผู้อื่นให้ไว้:

เรามีภาษามากมายพร้อมตัวละครมากมายที่คอมพิวเตอร์ควรแสดง Unicode จะกำหนดหมายเลขที่ไม่ซ้ำกันหรือจุดรหัสให้กับอักขระแต่ละตัว

คอมพิวเตอร์จัดการกับตัวเลขเช่นไบต์ ... การข้ามบิตของประวัติที่นี่และละเว้นการแก้ไขปัญหาหน่วยความจำคอมพิวเตอร์ 8 บิตจะจัดการไบต์ 8 บิตเนื่องจากหน่วยตัวเลขที่ใหญ่ที่สุดแสดงได้อย่างง่ายดายบนฮาร์ดแวร์คอมพิวเตอร์ 16 บิตจะขยายตัว ที่ถึงสองไบต์และอื่น ๆ

การเข้ารหัสอักขระเก่าเช่น ASCII นั้นมาจากยุค (pre-) 8-bit และพยายามยัดเยียดภาษาที่โดดเด่นในการคำนวณในเวลานั้นเช่นภาษาอังกฤษเป็นตัวเลขตั้งแต่ 0 ถึง 127 (7 บิต) ด้วยตัวอักษร 26 ตัวทั้งในรูปแบบตัวพิมพ์ใหญ่และไม่ใช่ตัวพิมพ์ใหญ่ตัวเลขและเครื่องหมายวรรคตอนที่ทำงานได้ค่อนข้างดี ASCII ขยายเวลาไปอีก 8 บิตสำหรับภาษาอื่น ๆ ที่ไม่ใช่ภาษาอังกฤษ แต่จะมีการเพิ่มหมายเลข 128 / รหัสจุดเพิ่มเติมให้โดยการขยายตัวนี้จะถูกแมปกับอักขระที่แตกต่างกันขึ้นอยู่กับภาษาที่แสดง มาตรฐาน ISO-8859 เป็นรูปแบบทั่วไปของการทำแผนที่นี้ ISO-8859-1 และ ISO-8859-15 (หรือที่เรียกว่า ISO-Latin-1, latin1 และใช่มีมาตรฐาน ISO 8859 สองรุ่นที่แตกต่างกันเช่นกัน)

แต่นั่นยังไม่เพียงพอเมื่อคุณต้องการแสดงอักขระจากภาษามากกว่าหนึ่งภาษาดังนั้นการยัดเยียดอักขระที่มีอยู่ทั้งหมดให้เป็นไบต์เดียวจะไม่ทำงาน

มีการเข้ารหัสที่แตกต่างกันสองประเภท: หนึ่งขยายช่วงค่าโดยการเพิ่มบิตเพิ่มเติม ตัวอย่างของการเข้ารหัสเหล่านี้จะเป็น UCS2 (2 ไบต์ = 16 บิต) และ UCS4 (4 ไบต์ = 32 บิต) พวกเขาประสบปัญหาเดียวกันกับมาตรฐาน ASCII และ ISO-8859 โดยเนื้อแท้เนื่องจากช่วงค่ายังคงมี จำกัด แม้ว่าขีด จำกัด จะสูงขึ้นอย่างมากมาย

การเข้ารหัสประเภทอื่นใช้จำนวนตัวแปรไบต์ต่อตัวอักษรและการเข้ารหัสที่รู้จักกันมากที่สุดสำหรับสิ่งนี้คือการเข้ารหัส UTF การเข้ารหัส UTF ทั้งหมดทำงานในลักษณะเดียวกันโดยประมาณ: คุณเลือกขนาดหน่วยซึ่งสำหรับ UTF-8 คือ 8 บิตสำหรับ UTF-16 คือ 16 บิตและสำหรับ UTF-32 คือ 32 บิต มาตรฐานจะกำหนดบิตเหล่านี้บางส่วนเป็นแฟล็ก: หากพวกเขาถูกตั้งค่าหน่วยถัดไปในลำดับหน่วยจะถือว่าเป็นส่วนหนึ่งของตัวละครเดียวกัน หากพวกเขาไม่ได้ตั้งค่าหน่วยนี้แสดงถึงตัวละครตัวหนึ่งอย่างเต็มที่ ดังนั้นตัวอักษรที่พบบ่อยที่สุด (ภาษาอังกฤษ) จะครอบครองหนึ่งไบต์ใน UTF-8 (สองใน UTF-16, 4 ใน UTF-32) แต่อักขระภาษาอื่น ๆ สามารถมีขนาดหกไบต์ขึ้นไป

การเข้ารหัสหลายไบต์ (ฉันควรจะบอกว่าหลายหน่วยหลังจากคำอธิบายข้างต้น) มีข้อได้เปรียบที่ค่อนข้างมีประสิทธิภาพในพื้นที่ แต่ข้อเสียที่การดำเนินการเช่นการค้นหาสตริงย่อยการเปรียบเทียบและอื่น ๆ ทั้งหมดต้องถอดรหัสอักขระเป็นรหัส Unicode คะแนนก่อนการดำเนินการดังกล่าวสามารถทำได้ (มีทางลัดบางส่วน)

ทั้งมาตรฐาน UCS และ UTF เข้ารหัสจุดรหัสตามที่กำหนดไว้ใน Unicode ในทางทฤษฎีการเข้ารหัสเหล่านั้นสามารถใช้ในการเข้ารหัสหมายเลขใด ๆ (ภายในช่วงที่รองรับการเข้ารหัส) - แต่แน่นอนการเข้ารหัสเหล่านี้ถูกสร้างขึ้นเพื่อเข้ารหัสจุดรหัส Unicode และนั่นคือความสัมพันธ์ของคุณระหว่างพวกเขา

Windows จัดการกับสตริงที่เรียกว่า "Unicode" เป็นสตริง UTF-16 ในขณะที่ UNIX ส่วนใหญ่ใช้ค่าเริ่มต้นเป็น UTF-8 ในปัจจุบัน โปรโตคอลการสื่อสารเช่น HTTP มีแนวโน้มที่จะทำงานได้ดีที่สุดกับ UTF-8 เนื่องจากขนาดของหน่วยใน UTF-8 เหมือนกับใน ASCII และโปรโตคอลส่วนใหญ่นั้นได้รับการออกแบบในยุค ASCII ในทางกลับกัน UTF-16 ให้ประสิทธิภาพพื้นที่ / การประมวลผลเฉลี่ยที่ดีที่สุดเมื่อแสดงภาษาที่มีชีวิตทั้งหมด

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

หวังว่าจะเติมในรายละเอียดบางอย่าง


9
โดยทั่วไปแล้ว UCS-2 และ UCS-4 เป็นชุดอักขระไม่ใช่การเข้ารหัสอักขระ (จึงเป็นชื่อ)
หอยทากเครื่องกล

74
@Tuukka ข้อผิดพลาดในการโพสต์นี้เป็นจำนวนมาก มี ISO 8859 มากกว่า 2 รุ่น ASCII ไม่ได้ทำงานกับภาษาอังกฤษสิ่งที่ขาดหายไปเช่นเครื่องหมายคำพูดแบบโค้งเซ็นต์เครื่องหมายเน้นเสียงและอีกมากมาย - Unicode ไม่ได้เป็นเพียงแค่ภาษาอังกฤษเท่านั้น ภาษาอังกฤษก็ต้องการเช่นกัน !! ไม่มี codepoints ที่ครอบครองมากกว่า 4 ไบต์ในการเข้ารหัสใด ๆ ธุรกิจขนาด 6 ไบต์ผิดพลาด คุณไม่สามารถเข้ารหัส UTF ค่าสเกลาร์ Unicode ใด ๆ ได้ตามที่กล่าวว่า: ตัวแทน & ตัวอักษรอื่นที่ไม่ได้รับอนุญาตทั้งหมด 66 ตัว UCS-4 และ UTF-32 ไม่เหมือนกัน ไม่มี UTF-32 หลายหน่วย UTF-16 ไม่ได้มีประสิทธิภาพเท่าที่พวกเขาแกล้ง - & c & c & c!
tchrist

1
ASCII ยังไม่มีเครื่องหมายปอนด์£และแน่นอนว่าไม่มีเครื่องหมายยูโร€ (ซึ่งมีอายุน้อยกว่า ASCII)
TRiG

1
@tchrist ดูเหมือนว่า 6 ไบต์นั้นไม่น่าจะเป็นไปได้ ดูสิ่งนี้: joelonsoftware.com/articles/Unicode.htmlซึ่งแสดงว่ามีพื้นที่อักขระจาก0x04000000ถึง0x7FFFFFFFหรือเป็นไบนารี1111110v 10vvvvvv 10vvvvvv 10vvvvvv 10vvvvvv 10vvvvvv - และนั่นคือ 6 ไบต์ อย่างไรก็ตาม 6 ไบต์เป็นค่าสูงสุดและไม่เป็นบทความที่อ้างสิทธิ์อย่างสับสน "หกไบต์หรือมากกว่า "
ไวยากรณ์

12
@syntaxerror: "มีเพียงรหัสจุด 128 ขึ้นไปเท่านั้นที่ถูกจัดเก็บโดยใช้ 2, 3, ในความเป็นจริงสูงสุด 6 ไบต์" ถูกต้องเมื่อเขียน แต่ต่อมาในปีเดียวกันนั้น (สิบสองปีก่อน) มันถูกต้อง en.wikipedia.org/wiki/UTF-8กล่าวว่า "สเปคดั้งเดิมครอบคลุมตัวเลขได้สูงสุด 31 บิต (ขีด จำกัด ดั้งเดิมของชุดอักขระสากล) ในเดือนพฤศจิกายน 2546 UTF-8 ถูก จำกัด โดย RFC 3629 ถึงสิ้นสุดที่ U + 10FFFF เพื่อให้ตรงกับข้อ จำกัด ของการเข้ารหัสอักขระ UTF-16 สิ่งนี้จะลบลำดับ 5 และ 6 ไบต์ทั้งหมดและประมาณครึ่งหนึ่งของลำดับ 4 ไบต์ "
Mooing Duck

237

ให้ฉันใช้ตัวอย่างเพื่ออธิบายหัวข้อนี้:

A chinese character:      汉
it's unicode value:       U+6C49
convert 6C49 to binary:   01101100 01001001

ไม่มีอะไรน่าอัศจรรย์เลยมันง่ายมาก ตอนนี้สมมติว่าเราตัดสินใจที่จะเก็บตัวละครตัวนี้ไว้ในฮาร์ดไดรฟ์ของเรา ในการทำเช่นนั้นเราต้องจัดเก็บอักขระในรูปแบบไบนารี เราสามารถจัดเก็บได้ง่ายเช่นเดียวกับ '01101100 01001001' ทำ!

แต่เดี๋ยวก่อนนั่นคือ '01101100 01001001' หนึ่งตัวอักษรหรือสองตัวอักษร? คุณรู้ว่านี่คือตัวละครตัวหนึ่งเพราะฉันบอกคุณ แต่เมื่อคอมพิวเตอร์อ่านมันก็ไม่มีความคิด ดังนั้นเราจึงจำเป็นต้องมี "การเข้ารหัส" เพื่อบอกคอมพิวเตอร์ว่าเป็นหนึ่งเดียว

นี่คือที่มาของกฎของ 'UTF-8': http://www.fileformat.info/info/unicode/utf8.htm

Binary format of bytes in sequence

1st Byte    2nd Byte    3rd Byte    4th Byte    Number of Free Bits   Maximum Expressible Unicode Value
0xxxxxxx                                                7             007F hex (127)
110xxxxx    10xxxxxx                                (5+6)=11          07FF hex (2047)
1110xxxx    10xxxxxx    10xxxxxx                  (4+6+6)=16          FFFF hex (65535)
11110xxx    10xxxxxx    10xxxxxx    10xxxxxx    (3+6+6+6)=21          10FFFF hex (1,114,111)

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

Header  Place holder    Fill in our Binary   Result         
1110    xxxx            0110                 11100110
10      xxxxxx          110001               10110001
10      xxxxxx          001001               10001001

เขียนผลลัพธ์ในหนึ่งบรรทัด:

11100110 10110001 10001001

นี่คือค่า UTF-8 (ไบนารี) ของตัวอักษรจีน! (ยืนยันด้วยตนเอง: http://www.fileformat.info/info/unicode/char/6c49/index.htm )

สรุป

A chinese character:      汉
it's unicode value:       U+6C49
convert 6C49 to binary:   01101100 01001001
embed 6C49 as UTF-8:      11100110 10110001 10001001

ป.ล. ถ้าคุณต้องการเรียนรู้หัวข้อนี้ในไพ ธ อนคลิกที่นี่


6
"แต่เดี๋ยวก่อนนั่นคือ '01101100 01001001' หนึ่งตัวละครหรือสองตัวอักษร? คุณรู้ว่านี่เป็นตัวละครตัวหนึ่งเพราะฉันบอกคุณ แต่เมื่อคอมพิวเตอร์อ่านมันไม่มีความคิดดังนั้นเราต้องมี" การเข้ารหัส "เพื่อ บอกคอมพิวเตอร์ให้ถือว่าเป็นหนึ่งเดียว " โอเค แต่คอมพิวเตอร์ก็ยังไม่รู้ว่ามันควรเข้ารหัสด้วย utf-8 ใช่ไหม
Koray Tugay

15
@KorayTugay คอมพิวเตอร์ไม่ทราบว่าควรใช้การเข้ารหัสแบบใด คุณต้องบอกเมื่อคุณบันทึกอักขระลงในไฟล์และเมื่อคุณอ่านอักขระจากไฟล์
เฉิง

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

2
ดังนั้นส่วนหัวเหล่านั้นตีความอย่างไร ถ้าฉันดูที่ตารางแรกฉันคิดว่า: ถ้า byte เริ่มต้นด้วย bit 0ตัวละครจะถูกแทนด้วย 1 กัด (ปัจจุบันหนึ่ง) ถ้า byte เริ่มต้นด้วย110แล้วตัวละครจะถูกแทนด้วย 2 ไบต์ (ปัจจุบันและต่อไป ( บิตที่เหลือหลังจาก10)) หากไบต์เริ่มต้นด้วย1110อักขระจะถูกแทนด้วย 3 ไบต์ปัจจุบันและ 2 ไบต์ถัดไป (บิตที่เหลือหลังจาก10)
JBoy

2
อ่าน 10 บทความเกี่ยวกับ UTF-8 หลังจากอ่านสิ่งนี้ฉันเข้าใจภายใน 10 วินาที :)
jrhee17

201

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

UTF-8เป็นการเข้ารหัสอักขระ - วิธีการแปลงจากลำดับของไบต์ไปเป็นลำดับอักขระและในทางกลับกัน ครอบคลุมทั้งชุดอักขระ Unicode ASCII ถูกเข้ารหัสเป็นไบต์เดียวต่อตัวอักษรและอักขระอื่น ๆ ใช้ไบต์มากขึ้นโดยขึ้นอยู่กับจุดรหัสที่แน่นอน (สูงสุด 4 ไบต์สำหรับจุดรหัสที่กำหนดไว้ทั้งหมดในปัจจุบันเช่นสูงถึง U-0010FFFF และแน่นอน 4 ไบต์สามารถรับมือได้ถึง U-001FFFFF)

เมื่อใช้ "Unicode" เป็นชื่อของการเข้ารหัสอักขระ (เช่นคุณสมบัติ. NET Encoding.Unicode ) มักจะหมายถึงUTF-16ซึ่งเข้ารหัสอักขระที่พบบ่อยที่สุดเป็นสองไบต์ บางแพลตฟอร์ม (โดยเฉพาะ. NET และ Java) ใช้ UTF-16 เป็นการเข้ารหัสอักขระ "ดั้งเดิม" สิ่งนี้นำไปสู่ปัญหาที่มีขนหากคุณจำเป็นต้องกังวลเกี่ยวกับตัวละครที่ไม่สามารถเข้ารหัสในค่า UTF-16 เดียว (พวกเขาถูกเข้ารหัสเป็น "คู่ตัวแทน") - แต่นักพัฒนาส่วนใหญ่ไม่เคยกังวลเกี่ยวกับเรื่องนี้ IME

การอ้างอิงบางอย่างเกี่ยวกับ Unicode:


16
ฉันคิดว่า UTF-16 เท่ากับ "Unicode" บนแพลตฟอร์ม Windows เท่านั้น ผู้คนมักจะใช้ UTF-8 ตามค่าเริ่มต้นบน * ระวัง +1 แต่คำตอบที่ดี
jalf

10
@Chris: ไม่ ISO-8859-1 ไม่ใช่ UTF-8 UTF-8 เข้ารหัส U + 0080 ถึง U + 00FF เป็นสองไบต์ไม่ใช่หนึ่ง Windows 1252 และ ISO-8859-1 ส่วนใหญ่เหมือนกัน แต่พวกเขาต่างกันระหว่างค่า 0x80 และ 0x99 ถ้าฉันจำได้อย่างถูกต้องโดยที่ ISO 8859-1 มี "รู" แต่ CP1252 กำหนดอักขระ
Jon Skeet

13
แนวคิดของการโทร UTF-16 "Unicode" อยู่กับฉันอย่างไม่สะดวกเนื่องจากมีความเป็นไปได้ที่จะเกิดความสับสน - แม้ว่าสิ่งนี้จะชี้ให้เห็นอย่างชัดเจนว่าเป็นการประชุม. NET เท่านั้น UTF-16 เป็นวิธีการแทน Unicode แต่ไม่ใช่ "การเข้ารหัส Unicode"
thomasrutter

6
@unwesen: UTF-8 ไม่จำเป็นต้องมีคู่ตัวแทน เพียงแสดงถึงอักขระที่ไม่ใช่ BMP โดยใช้ลำดับไบต์ที่ยาวขึ้นอย่างต่อเนื่อง
Jon Skeet

5
@RoyiNamir: ใช่ "Unicode" มักจะถูกใช้เพื่อหมายถึง "UTF-16" โดยเฉพาะใน Windows
Jon Skeet

108

มันไม่เหมือนกัน - UTF-8 เป็นวิธีการเข้ารหัส Unicode โดยเฉพาะ

มีการเข้ารหัสที่แตกต่างกันมากมายที่คุณสามารถเลือกได้ขึ้นอยู่กับแอปพลิเคชันของคุณและข้อมูลที่คุณต้องการใช้ ที่พบมากที่สุดคือ UTF-8, UTF-16 และ UTF-32 s เท่าที่ฉันรู้


10
อย่างไรก็ตามประเด็นคือผู้แก้ไขบางรายเสนอให้บันทึกไฟล์เป็น "Unicode" หรือ "UTF-8" ดังนั้นการกล่าวถึง "Unicode" ในกรณีนั้นคือ UTF-16 ฉันเชื่อว่าจำเป็น
serhio

71

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


2
อย่างไรก็ตามประเด็นคือผู้แก้ไขบางรายเสนอให้บันทึกไฟล์เป็น "Unicode" หรือ "UTF-8" ดังนั้นการกล่าวถึง "Unicode" ในกรณีนั้นคือ UTF-16 ฉันเชื่อว่าจำเป็น
serhio

ตัวเลขที่นำเสนอตัวละครทำเช่นกันเช่น ASCII
bright

6
อ่านก่อนและหลังดูคำตอบที่เหลือในหน้านี้
Dodgie

33

Unicodeเป็นมาตรฐานที่กำหนดพร้อมกับ ISO / IEC 10646, ชุดอักขระสากล (UCS)ซึ่งเป็นชุดอักขระที่มีอยู่ทั้งหมดที่จำเป็นในการเป็นตัวแทนของภาษาที่รู้จักทั้งหมด

Unicode กำหนดชื่อและหมายเลข ( รหัสอักขระหรือรหัสจุด ) ให้กับอักขระแต่ละตัวในรายการ

การเข้ารหัส UTF-8เป็นวิธีการแสดงอักขระเหล่านี้แบบดิจิทัลในหน่วยความจำคอมพิวเตอร์ UTF-8 จับคู่แต่ละจุดรหัสในลำดับของ octets (8 บิต)

สำหรับเช่น

UCS Character = Unicode Han Character

UCS code-point = U + 24B62

การเข้ารหัส UTF-8 = F0 A4 โฆษณา A2 (ฐานสิบหก) = 11110000 10100100 10101101 10100010 (bin)


ไม่ UTF-8 แมป codepoints เป็นลำดับที่มากกว่า 127 ทุกอย่างจาก 0 ถึง 127 ไม่ใช่ลำดับ แต่เป็นไบต์เดียว Btw, ASCII ยังกำหนดชื่อของอักขระให้กับตัวเลขดังนั้นนี่คือสิ่งที่ Unicode ทำ แต่ Unicode ไม่ได้หยุดที่ codepoint 127 แต่ไปถึง 0x10ffff
bright

2
@brightly ฉันแตกต่างกัน อักขระ Ascii ถูกแมปกับลำดับไบต์เดียว บิตแรกซึ่งเป็น 0 ในกรณีของโค้ดสำหรับอักขระ ASCII ระบุจำนวนไบต์ที่ตามมา - ศูนย์ http://www.wikiwand.com/en/UTF-8#/Descriptionดูที่แถวแรก
nightlytrails

สำหรับฉันลำดับประกอบด้วยมากกว่าหนึ่งไบต์ อักขระ ASCII ภายใน UTF-8 เป็นไบต์เดียวตามที่มีบิตที่สำคัญที่สุดตั้งไว้ที่ 0 Codepoints ที่สูงกว่า 127 จากนั้นต้องการลำดับซึ่งมักจะมี startbyte และหนึ่งหรือสองหรือสามไบต์ต่อไปนี้ แล้วทำไมคุณถึงเรียกว่า "ลำดับ" หนึ่งไบต์?
สดใส

ดี ... หลายครั้งที่นักกฎหมายด้านภาษาอังกฤษสามารถงงงันกับเรื่องนี้ในทางที่ผิดโดยเจตนาในซอฟต์แวร์ เป็นกรณีเดียวกันที่นี่ คุณสามารถโต้เถียงมัน แต่นั่นจะไม่ทำให้ชัดเจนขึ้น
nightlytrails

1
@brighty Hmmm, ในวิชาคณิตศาสตร์, ลำดับของ 0องค์ประกอบตกลง ลำดับของ 1 องค์ประกอบก็ดีเช่นกัน
chux - Reinstate Monica

24

Unicodeเป็นเพียงมาตรฐานที่กำหนดชุดอักขระ ( UCS ) และการเข้ารหัส ( UTF ) เพื่อเข้ารหัสชุดอักขระนี้ แต่โดยทั่วไปแล้ว Unicode จะอ้างอิงถึงชุดอักขระไม่ใช่มาตรฐาน

อ่านแน่นอนทุกขั้นต่ำของผู้พัฒนาซอฟท์แวแน่นอนบวกต้องทราบเกี่ยวกับ Unicode และชุดตัวอักษร (ไม่มีข้อแก้ตัว!)และUnicode ใน 5 นาที


1
@serhio: ฉันรู้ แม้ว่าจะมีการเข้ารหัส UTF-16 สามแบบที่แตกต่างกัน: UTF-16LEและUTF-16BE ที่ชัดเจนสองชุดและUTF-16โดยนัยซึ่งระบุ endianness ด้วย BOM
Gumbo

@Gumbo: การขาด BOM ไม่ได้หมายความว่าเป็นการเข้ารหัสที่แตกต่าง มีการเข้ารหัสสองเท่านั้น
Mooing Duck

บล็อกด้านบนเขียนโดย CEO ของ Stakcoverflow
Shailesh Pratapwar

23

คำตอบที่มีอยู่แล้วอธิบายรายละเอียดมากมาย แต่นี่เป็นคำตอบสั้น ๆ พร้อมคำอธิบายและตัวอย่างที่ตรงที่สุด

Unicode เป็นมาตรฐานที่แมปอักขระกับ codepoints
อักขระแต่ละตัวมี codepoint ที่ไม่ซ้ำกัน (หมายเลขประจำตัว) ซึ่งเป็นหมายเลขเช่น 9731

UTF-8 เป็นการเข้ารหัสของ codepoints
เพื่อจัดเก็บอักขระทั้งหมดบนดิสก์ (ในไฟล์) UTF-8 จะแยกอักขระออกเป็น 4 octets (ลำดับ 8 บิต) - ไบต์ UTF-8 เป็นหนึ่งในการเข้ารหัสหลายวิธี (วิธีการแทนข้อมูล) ตัวอย่างเช่นใน Unicode codepoint (ทศนิยม) 9731 หมายถึง snowman ( ) ซึ่งประกอบด้วย 3 ไบต์ใน UTF-8:E2 98 83

นี่เป็นรายการที่เรียงลำดับด้วยตัวอย่างแบบสุ่มบาง


1
No! UTF-8 เป็นวิธีที่ดีในการเข้ารหัสอักขระ Unicode แต่เราสามารถเข้ารหัสได้ใน UTF-16 หรือ UTF-32 ด้วย UTF-32 เรามีความสัมพันธ์ 1: 1 ระหว่าง DWORD และ codepoint ด้วย UTF-16 เรามีความสัมพันธ์ 1: 1 ระหว่าง WORD และ codepoint เฉพาะสำหรับ codepoints ของ BMP เท่านั้นไม่รวมตัวแทนและ BOM ใน UTF-8 เรามีความสัมพันธ์แบบ 1: 1 ระหว่างไบต์และ codepoint สำหรับ codepoints <127
สว่าง

5
@brighty: ใช่ แต่ทำไม "ไม่!" ฉันเขียนว่า "UTF-8 เป็นหนึ่งในการเข้ารหัสหลายอย่าง" เพราะยังมี UTF-16 และ UTF-32
พื้นฐาน 6

16

1. Unicode

มีตัวละครมากมายทั่วโลกเช่น "$, &, h, a, t,?, 张, 1, =, + ... "

จากนั้นก็มีองค์กรที่อุทิศตนให้กับตัวละครเหล่านี้

พวกเขาสร้างมาตรฐานที่เรียกว่า "Unicode"

มาตรฐานมีดังนี้:

  • สร้างแบบฟอร์มที่แต่ละตำแหน่งเรียกว่า "จุดรหัส" หรือ "ตำแหน่งรหัส"
  • ตำแหน่งทั้งหมดมาจาก U + 0000 ถึง U + 10FFFF;
  • จนถึงตอนนี้บางตำแหน่งจะเต็มไปด้วยตัวละครและตำแหน่งอื่น ๆ จะถูกบันทึกหรือว่างเปล่า
  • ตัวอย่างเช่นตำแหน่ง "U + 0024" ถูกเติมด้วยอักขระ "$"

PS: แน่นอนว่ามีองค์กรอื่นที่เรียกว่า ISO รักษามาตรฐานอื่น - "ISO 10646", เกือบเหมือน

2. UTF-8

ดังที่กล่าวข้างต้น U + 0024 เป็นเพียงตำแหน่งดังนั้นเราจึงไม่สามารถบันทึก "U + 0024" ในคอมพิวเตอร์สำหรับตัวละคร "$"

จะต้องมีวิธีการเข้ารหัส

จากนั้นก็มีวิธีการเข้ารหัสเช่น UTF-8, UTF-16, UTF-32, UCS-2 ....

ภายใต้ UTF-8 จุดรหัส "U + 0024" จะถูกเข้ารหัสเป็น 00100100

00100100 คือค่าที่เราบันทึกไว้ในคอมพิวเตอร์สำหรับ "$"


1
โดยทั่วไป UTF-8 เป็นตัวแปรเดียวที่ทุกคนใช้ในปัจจุบัน
Rick James

2
ISO 10646 เป็นมาตรฐานที่เหมือนกันกับชุดอักขระ Unicode Unicode กำหนดสิ่งต่าง ๆ มากมายนอกเหนือจากชุดอักขระเช่นกฎสำหรับการเรียงลำดับเคสและอื่น ๆ ISO 10646 เป็นเพียงชุดอักขระ (ซึ่งปัจจุบันมีมากกว่า 130,000) Unicode Consortium และ ISO พัฒนา Unicode ร่วมกับ ISO ที่เกี่ยวข้องเฉพาะกับชุดอักขระและการเข้ารหัสและ Unicode ยังกำหนดคุณสมบัติของตัวอักษรและกฎสำหรับการประมวลผลข้อความ
thomasrutter

12

ฉันได้ตรวจสอบลิงก์ในคำตอบของ Gumbo และฉันต้องการวางบางส่วนของสิ่งเหล่านี้ที่นี่เพื่ออยู่ใน Stack Overflow เช่นกัน

"... บางคนตกอยู่ภายใต้ความเข้าใจผิดว่า Unicode เป็นเพียงรหัส 16 บิตที่ตัวละครแต่ละตัวใช้เวลา 16 บิตและดังนั้นจึงมีตัวอักษรที่เป็นไปได้ 65,536 ตัวที่จริงแล้วไม่ถูกต้องมันเป็นตำนานที่พบบ่อยที่สุดเกี่ยวกับ Unicode ดังนั้นถ้าคุณคิดอย่างนั้นอย่ารู้สึกแย่

ในความเป็นจริง Unicode มีวิธีคิดต่าง ๆ เกี่ยวกับตัวละครต่างกันและคุณต้องเข้าใจวิธีคิดแบบ Unicode เกี่ยวกับสิ่งต่าง ๆ หรือไม่มีอะไรที่สมเหตุสมผล

จนถึงตอนนี้เราได้สันนิษฐานว่าตัวอักษรจับคู่กับบิตที่คุณสามารถเก็บไว้ในดิสก์หรือในหน่วยความจำ:

A -> 0100 0001

ใน Unicode จดหมายจะจับคู่สิ่งที่เรียกว่ารหัสจุดซึ่งยังคงเป็นแนวคิดทางทฤษฎี จุดโค้ดนั้นถูกแสดงในหน่วยความจำหรือบนดิสก์เป็นเรื่องราวอื่นทั้งหมด ... "

"... จดหมายสงบทุกตัวในตัวอักษรทุกตัวได้รับหมายเลขเวทมนตร์จากกลุ่มยูนิโคดซึ่งเขียนเช่นนี้: U + 0639 หมายเลขเวทย์มนตร์นี้เรียกว่ารหัสจุด U + หมายถึง" Unicode "และตัวเลขเป็นเลขฐานสิบหก U + 0639 เป็นตัวอักษรภาษาอาหรับ Ain ตัวอักษรภาษาอังกฤษ A จะเป็น U + 0041 .... "

"... ตกลงเอาล่ะเรามีสตริง:

สวัสดี

ซึ่งใน Unicode สอดคล้องกับจุดโค้ดทั้งห้านี้:

U + 0048 U + 0065 U + 006C U + 006C U + 006F

เพียงจุดโค้ดจำนวนมาก ตัวเลขจริงๆ เรายังไม่ได้พูดอะไรเกี่ยวกับวิธีการจัดเก็บในหน่วยความจำหรือเป็นตัวแทนในข้อความอีเมล ... "

"... นั่นคือที่มาของการเข้ารหัส

แนวคิดแรกสุดสำหรับการเข้ารหัส Unicode ซึ่งนำไปสู่ตำนานเกี่ยวกับสองไบต์คือเฮ้เราแค่เก็บตัวเลขเหล่านั้นในสองไบต์ต่อกัน ดังนั้นสวัสดีกลายเป็น

00 48 00 65 00 6C 00 6C 00 6F

ขวา? ไม่เร็วมาก! เป็นไปไม่ได้:

48 00 65 00 6C 00 6C 00 6F 00 ..."


ใน ASCII ตัวอักษรจะจับคู่กับ codepoint เช่นกันไม่ใช่เฉพาะใน Unicode
bright

8

UTF-8เป็นหนึ่งในรูปแบบการเข้ารหัสที่เป็นไปได้สำหรับข้อความUnicode

Unicodeเป็นมาตรฐานที่มีขอบเขตกว้างซึ่งกำหนดได้มากกว่า 130,000 ตัวอักษรและจัดสรรรหัสตัวเลขแต่ละตัว (จุดรหัส) นอกจากนี้ยังกำหนดกฎสำหรับวิธีการจัดเรียงข้อความนี้ทำให้เป็นมาตรฐานเปลี่ยนกรณีและอื่น ๆ อักขระใน Unicode จะถูกแทนด้วยจุดรหัสจากศูนย์ถึง 0x10FFFF รวมถึงแม้ว่าบางจุดรหัสจะถูกจองและไม่สามารถใช้สำหรับตัวอักษร

มีมากกว่าหนึ่งวิธีที่สตริงของจุดโค้ด Unicode สามารถเข้ารหัสเป็นสตรีมไบนารี่ได้ สิ่งเหล่านี้เรียกว่า "การเข้ารหัส" การเข้ารหัสที่ตรงไปตรงมาที่สุดคือUTF-32ซึ่งจะเก็บรหัสจุดแต่ละจุดเป็นจำนวนเต็ม 32 บิตโดยแต่ละอันมีความกว้าง 4 ไบต์

UTF-8เป็นอีกการเข้ารหัสและกำลังกลายเป็นมาตรฐานแบบพฤตินัยเนื่องจากมีข้อได้เปรียบกว่า UTF-32 และอื่น ๆ UTF-8 เข้ารหัสเป็นลำดับของค่าไบต์เดียว จุดรหัสแต่ละจุดสามารถใช้หมายเลขตัวแปรของค่าไบต์เหล่านี้ จุดรหัสในช่วง ASCII นั้นมีการเข้ารหัสเปลือยเพื่อให้เข้ากันได้กับ ASCII จุดรหัสที่อยู่นอกช่วงนี้ใช้จำนวนตัวแปรไบต์ทั้ง 2, 3, หรือ 4 ขึ้นอยู่กับช่วงที่พวกเขาอยู่

UTF-8 ได้รับการออกแบบโดยคำนึงถึงคุณสมบัติเหล่านี้:

  • อักขระ ASCII ถูกเข้ารหัสตามที่มีอยู่ใน ASCII เช่นสตริง ASCII เป็นสตริง UTF-8 ที่ถูกต้องเช่นกัน

  • การเรียงลำดับแบบไบนารี: การเรียงลำดับสตริง UTF-8 โดยใช้การเรียงลำดับแบบไบนารีที่ไร้เดียงสาจะยังคงส่งผลให้คะแนนโค้ดทั้งหมดเรียงตามลำดับตัวเลข

  • อักขระที่ต้องใช้หลายไบต์ไม่มีค่าไบต์ใด ๆ ในช่วง ASCII เพื่อให้แน่ใจว่าส่วนหนึ่งของพวกเขาไม่สามารถเข้าใจผิดว่าเป็นอักขระ ASCII นี่คือคุณสมบัติด้านความปลอดภัย

  • สามารถตรวจสอบ UTF-8 ได้อย่างง่ายดายและแตกต่างจากการเข้ารหัสอักขระอื่น ๆ โดยตัวตรวจสอบความถูกต้อง ข้อความในการเข้ารหัส 8 บิตหรือหลายไบต์อื่น ๆ จะไม่ค่อยผ่านการตรวจสอบว่าเป็น UTF-8

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


คู่ของจุดเล็ก ๆ น้อย ๆ : [1] ไม่ควร"อักขระ ASCII จะถูกเข้ารหัสตรงตามที่พวกเขาอยู่ในASCII "เปลี่ยนเป็น "อักขระ ASCII จะถูกเข้ารหัสตรงตามที่พวกเขาอยู่ในUTF-8 " ? [2] วลี"รหัสใน Unicode ... "ไม่ชัดเจน (สำหรับฉัน) คุณหมายถึง"Unicode code points ... "หรือไม่
skomisa

@skomisa สำหรับจุดที่ 1 ฉันหมายถึงการเข้ารหัสอักขระภายในช่วง ASCII นั้นเหมือนกันสำหรับ ASCII และสำหรับ UTF-8
thomasrutter

สำหรับจุดที่ 2 นั่นคือจุดที่ยุติธรรมและฉันจะแก้ไขเพื่อให้ชัดเจน
thomasrutter

2

พวกมันเหมือนกันใช่มั้ย

ไม่พวกเขาไม่ได้


ฉันคิดว่าประโยคแรกของหน้า Wikipedia ที่คุณอ้างถึงให้บทสรุปที่ดีและสั้น ๆ :

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

ทำอย่างละเอียด:

  • Unicodeเป็นมาตรฐานซึ่งกำหนดแผนที่จากตัวละครไปยังตัวเลขจุดโค้ดที่เรียกว่า(เช่นในตัวอย่างด้านล่าง) สำหรับการทำแผนที่เต็มคุณสามารถดูได้ที่นี่

    ! -> U+0021 (21),  
    " -> U+0022 (22),  
    \# -> U+0023 (23)
    
  • UTF-8 เป็นหนึ่งในวิธีการเข้ารหัสจุดรหัสเหล่านี้ในรูปแบบที่คอมพิวเตอร์สามารถเข้าใจ aka บิต กล่าวอีกนัยหนึ่งมันเป็นวิธี / อัลกอริทึมในการแปลงจุดโค้ดแต่ละจุดเป็นลำดับบิตหรือแปลงลำดับบิตเป็นจุดโค้ดเทียบเท่า โปรดทราบว่ามีการเข้ารหัสทางเลือกมากมายสำหรับ Unicode


โจเอลให้คำอธิบายที่ดีจริงๆและภาพรวมของประวัติศาสตร์ที่นี่


2

หากฉันอาจสรุปสิ่งที่ฉันรวบรวมจากกระทู้นี้:

Unicode 'แปล' ตัวอักษรหมายเลขลำดับ (ในรูปแบบทศนิยม)

à = 224

UTF-8 คือการเข้ารหัสที่ 'แปล' ตัวเลขเหล่านี้ไบนารีการแสดง

224 = 11000011 10100000

โปรดทราบว่าเรากำลังพูดถึงการแทนเลขฐานสองของ 224 ไม่ใช่รูปแบบไบนารีซึ่งเป็น 0b11100000


2

บทความนี้จะอธิบายรายละเอียดทั้งหมด http://kunststube.net/encoding/

การเขียนเพื่อบัฟเฟอร์

ถ้าคุณเขียนลงในบัฟเฟอร์ 4 ไบต์สัญลักษณ์ที่มีการเข้ารหัส UTF8 ไบนารีของคุณจะมีลักษณะดังนี้:

00000000 11100011 10000001 10000010

ถ้าคุณเขียนลงในบัฟเฟอร์ 4 ไบต์สัญลักษณ์ที่มีการเข้ารหัส UTF16 ไบนารีของคุณจะมีลักษณะดังนี้:

00000000 00000000 00110000 01000010

อย่างที่คุณเห็นขึ้นอยู่กับว่าคุณจะใช้ภาษาใดในเนื้อหาของคุณซึ่งจะส่งผลต่อความจำของคุณ

เช่นสำหรับสัญลักษณ์นี้โดยเฉพาะ: การเข้ารหัส UTF16 นั้นมีประสิทธิภาพมากกว่าเนื่องจากเรามี 2 ไบต์สำรองไว้ใช้สำหรับสัญลักษณ์ถัดไป แต่ไม่ได้หมายความว่าคุณต้องใช้ UTF16 สำหรับตัวอักษรญี่ปุ่น

การอ่านจากบัฟเฟอร์

ตอนนี้ถ้าคุณต้องการอ่านไบต์ข้างต้นคุณต้องรู้ว่าการเข้ารหัสนั้นถูกเขียนและถอดรหัสกลับอย่างถูกต้อง

เช่นถ้าคุณถอดรหัสสิ่งนี้: 00000000 11100011 10000001 10000010 เป็นการเข้ารหัสแบบ UTF16 คุณจะจบลงด้วยการไม่

หมายเหตุ: การเข้ารหัสและ Unicode เป็นสองสิ่งที่แตกต่างกัน Unicode เป็นตารางขนาดใหญ่ที่มีสัญลักษณ์แต่ละตัวจับคู่กับจุดรหัสที่ไม่ซ้ำ เช่นสัญลักษณ์ (ตัวอักษร) มี(จุดรหัส) : 30 42 (ฐานสิบหก) ในอีกทางหนึ่งการเข้ารหัสเป็นอัลกอริทึมที่แปลงสัญลักษณ์เป็นวิธีที่เหมาะสมกว่าเมื่อเก็บไว้กับฮาร์ดแวร์

30 42 (hex) - > UTF8 encoding - > E3 81 82 (hex), which is above result in binary.

30 42 (hex) - > UTF16 encoding - > 30 42 (hex), which is above result in binary.

ป้อนคำอธิบายรูปภาพที่นี่


บทความเชื่อมโยงที่ดีมากหวังว่ามันจะยังคงใช้งานอยู่
yolob 21

0

UTF-8เป็นวิธีการเข้ารหัสอักขระ Unicode โดยใช้ลำดับ 8 บิต

Unicodeเป็นมาตรฐานในการแสดงอักขระที่หลากหลายจากหลายภาษา


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