ดองบล็อคมานาน ได้หัวข้อเขียนซะที เป็นเรื่องเกี่ยวกับ ASCII, Unicode, UTF-8 และอื่นๆ เพื่อแก้ไขความสับสนของตัวเองด้วย อ่านมาหลายรอบ แต่จำไม่ได้ซะทีเหมือนกัน
ความแตกต่างระหว่าง Binary กับ Text
Text จริงๆ แล้วก็คือ Byte
ASCII Encoding
Code Page Encoding
Unicode
UTF-16
UTF ย่อมาจาก Unicode transformation format ถ้าแปลตรงตัวก็อาจจะเป็น “รูปแบบการเปลี่ยน Unicode” ซึ่งตรงกับสิ่งที่ทำก็คือเป็นมาตรฐานการเปลี่ยน Code point มาเป็นเป็นตัวเลข 16 bits หรือ 2 bytes เรียกว่า 1 unit code ซึ่งเก็บ Unicode ได้ตั้งแต่ช่วง U+0000 ถึง U+D7FF และ U+E000 ถึง U+FFFF โดยเรียก Code point ช่วงนี้ว่า Basic Multilingual Plane ภาษาญี่ปุ่น, จีนและไทยก็อยู่ในช่วงนี้ด้วย ตัวเลขของทั้ง Code point และตัวอักษรที่ถูกเข้ารหัสแบบ UTF-16 จะเท่ากันเป๊ะ เช่น ก มี Code point เป็น U+0E01 ตรงกับ UTF-16 นั่นคือ 0E01
UTF-16 ไม่ได้ใช้เพียงแค่ 16 bit หรือ 2 bytes เท่านั้น แต่ยังใช้ Surrogate pairs นั่นคือใช้ 2 unit codes (ทั้งหมดเป็น 32 bit หรือ 4 bytes) เพื่อแสดงตัวอักษร Unicode เพียงตัวเดียว ใช้เข้ารหัสตัวอักษรอยู่นอกเหนือจาก Basic Multilingual Plane ตัวอย่างเช่น Emoji เป็นต้น
BOM (อาจจะข้ามไปก็ได้)
UTF-16 ยังมีเรื่อง Byte order mark หรือ BOM เข้ามาเกี่ยวข้องด้วย โดยจะเป็นตัวระบุว่าเราเข้ารหัส UTF-16 แบบไหนระหว่าง Big-endian หรือ Little-endian (ต่อไปนี้ขอย่อเป็น BE และ LE) อธิบาย Endianness แบบง่ายๆ คือหมายถึงลำดับที่ใช้ในการแปลความหมายของ Byte ตัวอย่างง่ายๆ ในชีวิตประจำวันก็เช่น หนึ่งร้อยยี่สิบสาม จะถูกเขียนแทนด้วย 123 ซึ่งเป็นแบบ BE โดยเขียนตัวเลขหลักที่มีค่ามากที่สุดไว้ทางซ้ายมือและหลักที่มีค่าน้อยที่สุดไว้ทางขวามือ ในทางตรงกันข้าม ถ้าต้องการเขียนเลข หนึ่งร้อยยี่สิบสาม เป็นแบบ LE จะเขียนว่า 321 ซึ่งถ้าไม่รู้ว่าตัวเลขนี้ถูกเขียนแบบไหน ก็จะตีความผิดไปทันที UTF-16 มีปัญหาตรงนี้เพราะใช้ 2 bytes เพื่อเก็บข้อมูล ตัวอย่างเช่น ตัวอักษร a (U+0061) ถ้าถูกเข้ารหัสเป็น UTF-16 BE จะได้ 00 61 แต่ถ้าเป็น UTF-16 LE ก็จะได้ 61 00 ซึ่งไม่มีอะไรผิดเพราะขึ้นอยู่กับสถาปัตยกรรม
BOM ที่ว่านี้คือค่า U+FEFF ซึ่งถูกใส่ไว้ข้างหน้าโค้ดของจริงตัวแรก ถ้าทั้งฝั่งเข้ารหัสและฝั่งถอดรหัสใช้ Endianness เหมือนกัน ก็จะอ่านได้เป็นตัวอักษรตัวเดียวกัน (U+FEFF) แต่กลับกันถ้าฝั่งเข้ารหัสและฝั่งถอดรหัสไม่ได้ใช้ Endianness เดียวกัน พอเวลาอ่านเจอ BOM จะอ่านได้เป็นอีกค่าหนึ่งคือ U+FFFE ซึ่งตัวอักษรตัวนี้ก็ถูกกันเอาไว้เพื่อเป็น BOM แล้ว แต่ถ้าไม่มี BOM มาตรฐาน RFC 2781 ระบุว่าให้เดาว่าเป็น BE เสมอ แต่ในทางปฏิบัติ Windows ใช้ LE เป็นค่าเริ่มต้น (น่าจะเป็นเพราะ Intel ใช้ LE) และแอปพลิเคชันอื่นๆ ก็มีเดาไว้ว่าเป็น LE ด้วยเหมือนกัน
ตามมาตรฐานยังอนุญาติให้ระบุ Endianness เอาไว้ได้ จึงมี UTF-16BE และ UTF-16LE ด้วย และถ้าถูกระบุชัดเจนแล้ว ไม่จำเป็นต้องใส่ BOM ลงไปอีก แต่ถ้ายังมีอยู่ก็ให้จัดการเป็นตัวอักษร ZERO WIDTH NO-BREAK SPACE
นอกใช้ BOM เพื่อระบุ Endianness แล้ว Web browser ยังใช้ BOM เพื่อดู Encoding ด้วย
UTF-8
มาถึง UTF-8 ที่ทุกคนน่าจะได้ยินบ่อยที่สุดในตระกูล UTF เนื่องจากถูกนำไปกำหนดเป็นมาตรฐานการเข้ารหัสสำหรับมาตรฐานอื่นๆ; UTF-8 สามารถเข้ารหัส Unicode ได้ทุกตัวโดยไม่ต้องใช้ Surrogate pairs แล้ว เนื้อที่ที่ใช้ในการเก็บใช้หน่วย 8 bit = 1 code unit และใช้สูงสุด 4 code units (32 bit)
UTF-8 ถูกออกแบบมาให้ใช้ร่วมกับ ASCII ได้เพราะ UTF-8 ใช้จำนวนบิตน้อยที่สุดคือ 8 bit ตรงกันข้ามกับ UTF-16 ที่ใช้จำนวนบิตน้อยที่สุดคือ 16 bit จึงทำให้ใช้ร่วมกับ ASCII ไม่ได้ ตัวอย่างตัวอักษร a ที่เข้ารหัสเป็น ASCII จะได้(ทั้งหมดเป็นฐาน 16) 61, Unicode code Code point ของ a เท่ากับ U+0061 เมื่อเข้ารหัสเป็น UTF-16 จะได้ 0061 แต่ถ้าเข้ารหัสเป็น UTF-8 จะได้ 61 จะเห็นได้ว่า ถ้าเราเข้ารหัสด้วย ASCII และมาลองอ่านโดยถอดรหัสแบบ UTF-8 เราจะยังอ่านได้ถูกต้อง แต่ถ้ามาถอดรหัสเป็นแบบ UTF-16 เราจะอ่านไม่รู้เรื่อง
UTF-8 ยังถูกออกแบบมาให้แก้ปัญหาเรื่อง Endianness ไม่ตรงกันระหว่างผู้เข้ารหัสและถอดรหัส ทำให้ไม่จำเป็นต้องใช้ BOM อีกต่อไป แต่ก็ยังมีบางครั้งที่ใส่ BOM เข้าไปเพื่อให้สามารถระบุได้ว่าเป็น Data stream ของ UTF-8 แต่อาจจะมีปัญหากับเครื่องมือหรืออะไรก็ตามแต่ ที่อ่าน UTF-8 แต่ไม่ได้ต้องการจัดการกับ BOM ตัวอย่างแอปพลิเคชันที่ใส่ BOM เข้าไปใน UTF-8 คือ Notepad
UTF-32
UTF-32 ใช้ 32 bits = 1 code unit และใช้สูงสุดเพียงแค่ 1 code unit เท่านั้น ตัวเลขที่ได้จากการเข้ารหัส UTF-32 จะเท่ากับ Unicode Code point ทั้งหมด จบ…
(แถม) Binary to Text encoding
ข้างบนทั้งหมดเป็นการเก็บเอาตัวหนังสือไว้ในคอมด้วยการเข้ารหัสตัวอักษรไปเป็น binary แต่กลับกันก็มีการเข้ารหัส byte ไปเป็นตัวอักษรเพื่อใช้งานกับโปรโตคอลที่เป็น Text-based เช่น HTTP, JSON เป็นต้น และก็อยากที่กล่าวไว้ด้านบน ถ้าตัวอักษรที่ได้จากการเข้ารหัส Binary เหล่านี้จะเป็นต้องอยู่บนคอมพิวเตอร์ ก็ต้องถูกเข้ารหัสเป็น Binary อีกทีหนึ่งเสมอ (ยกเว้นจะพิมพ์ใส่กระดาษมาอ่าน แล้วลบทิ้ง – -*)
base64 encoding
เป็นมาตรฐานการเข้ารหัสจาก byte เป็น text ที่นิยมใช้สูงมาก ตรงตามชื่อคือมีตัวอักษรที่ถูกเลือกมาใช้ทั้งหมด 64 ตัว แต่ก็มีมาตรฐานย่อยๆ อีกซึ่งตัวอักษรทั้ง 64 ตัวอาจจะไม่เหมือนกันทุกตัว
คำถามที่อาจจะสงสัย
Q: ถ้า Unicode ไม่ใช่การเข้ารหัส แล้วทำไม Notepad บน Windows ถึงมี Unicode เป็นตัวเลือกเวลาเข้ารหัส
A: เพราะ UTF-16 เข้ารหัสตัวอักษรที่มีค่าเท่ากับ code point (เฉพาะ BMP) (คิดเอาเอง) Windows จึงเรียก Unicode