วันนี้ฉันใช้สคริปต์จาวาสคริปต์เพื่อสร้างเครื่องมือเมนูในหน้า ASP.NET และบันทึกเป็น menuScript.js ใช้ <script language="javascript" src="../js/MenuScript.js"></script ในหน้า >การโทร และเกิดปรากฏการณ์แปลกๆ ระหว่างดำเนินการ คือ ตัวอักษรจีนบนหน้าเว็บแสดงได้ตามปกติ แต่ตัวอักษรจีนในเมนูแสดงเป็นตัวอักษรที่อ่านไม่ออก
ไม่จำเป็นต้องถามหากคุณลองคิดดูว่ามีบางอย่างผิดปกติกับการเข้ารหัส สลับระหว่างการเข้ารหัส UTF-8 และ GB2312 ในตัวเลือก "ดู" - "การเข้ารหัส" ของหน้า ตัวอักษรบนหน้าและตัวอักษรจีนในเมนูสลับกันอ่านไม่ออก
วิธีแก้ไข: มีการตั้งค่าการเข้ารหัสในไฟล์คอนฟิกูเรชัน: <globalization requestEncoding="utf-8" responseEncoding="utf-8" />
มีตัวเลือกการเข้ารหัสเมื่อบันทึกไฟล์ menuScript.js (คุณสามารถเปิดไฟล์นี้ด้วย Word และบันทึกเป็นไฟล์อื่น เลือกการเข้ารหัส) เพียงรักษาการเข้ารหัสทั้งสองให้เหมือนกัน
เพื่อให้เข้าใจปัญหาการเข้ารหัสได้ดีขึ้น ฉันพบบทความเกี่ยวกับเรื่องนี้ใน CSDN ผู้แต่ง: fmddlmyy พิมพ์ซ้ำที่นี่เพื่อใช้อ้างอิง:
มาคุยเรื่องการเขียนโค้ดกันดีกว่า มาคุยเรื่องการเขียนโค้ด #region มาคุยเรื่องการเขียนโค้ดกัน
-
0. เอนเดียนใหญ่และเอนเดียนเล็ก
big endian และ little endian เป็นวิธีที่แตกต่างกันที่ CPU จัดการกับตัวเลขหลายไบต์ ตัวอย่างเช่น การเข้ารหัส Unicode ของอักขระ "汉" คือ 6C49 แล้วเมื่อเขียนลงไฟล์ 6C ควรเขียนไว้ข้างหน้าหรือ 49 ควรเขียนไว้ข้างหน้า? ถ้าเขียน 6C นำหน้า แสดงว่า big endian หรือเขียน 49 นำหน้า ซึ่งเป็นอักษรเอนเดียนเล็ก ๆ
คำว่า endian มาจากคำว่า Gulliver's Travels สงครามกลางเมืองในลิลลิพุตมีต้นกำเนิดมาจากการที่จะแยกไข่จากฝ่ายใหญ่ (Big-Endian) หรือฝ่ายเล็ก (Little-Endian) ส่งผลให้เกิดการกบฏขึ้น 6 ครั้ง จักรพรรดิองค์หนึ่งสิ้นพระชนม์ และ อีกคนหนึ่งสูญเสียบัลลังก์ของเขา
โดยทั่วไปเราแปล endian เป็น "ลำดับไบต์" และ endian ใหญ่และ endian เล็กเรียกว่า "big end" และ "little end"
1. การเข้ารหัสอักขระและโค้ดภายใน อย่างไรก็ตาม อักขระการเข้ารหัสอักขระภาษาจีนจะต้องได้รับการเข้ารหัสก่อนจึงจะสามารถประมวลผลโดยคอมพิวเตอร์ได้ วิธีการเข้ารหัสเริ่มต้นที่คอมพิวเตอร์ใช้คือรหัสภายในของคอมพิวเตอร์ คอมพิวเตอร์ในยุคแรกๆ ใช้การเข้ารหัส ASCII 7 บิต เพื่อประมวลผลอักขระภาษาจีน โปรแกรมเมอร์ได้ออกแบบ GB2312 สำหรับภาษาจีนตัวย่อ และ big5 สำหรับภาษาจีนตัวเต็ม
GB2312 (1980) มีอักขระทั้งหมด 7445 ตัว ซึ่งรวมถึงอักขระจีน 6763 ตัว และสัญลักษณ์อื่น ๆ อีก 682 ตัว ช่วงรหัสภายในของพื้นที่ตัวอักษรจีนคือจาก B0-F7 ในไบต์สูง A1-FE ในไบต์ต่ำ และบิตของโค้ดที่ถูกครอบครองคือ 72*94=6768 ในจำนวนนี้มีตำแหน่งงานว่าง 5 ตำแหน่ง ได้แก่ D7FA-D7FE
GB2312 รองรับตัวอักษรจีนน้อยเกินไป ข้อกำหนดการขยายอักขระภาษาจีนปี 1995 GBK1.0 ประกอบด้วยสัญลักษณ์ 21,886 ตัว ซึ่งแบ่งออกเป็นพื้นที่อักขระจีนและพื้นที่สัญลักษณ์กราฟิก พื้นที่อักขระภาษาจีนประกอบด้วยอักขระ 21,003 ตัว GB18030 ในปี 2000 เป็นมาตรฐานระดับชาติอย่างเป็นทางการซึ่งมาแทนที่ GBK1.0 มาตรฐานนี้ประกอบด้วยตัวอักษรจีน 27,484 ตัว รวมถึงภาษาทิเบต มองโกเลีย อุยกูร์ และภาษาชนกลุ่มน้อยหลักอื่นๆ แพลตฟอร์มพีซีปัจจุบันต้องรองรับ GB18030 และไม่มีข้อกำหนดสำหรับผลิตภัณฑ์แบบฝัง ดังนั้นโดยทั่วไปแล้วโทรศัพท์มือถือและ MP3 จะรองรับเฉพาะ GB2312 เท่านั้น
วิธีการเข้ารหัสเหล่านี้เข้ากันได้แบบย้อนหลังตั้งแต่ ASCII, GB2312, GBK ถึง GB18030 นั่นคืออักขระเดียวกันมักจะมีการเข้ารหัสเหมือนกันเสมอในรูปแบบเหล่านี้ และมาตรฐานในภายหลังรองรับอักขระมากขึ้น ในการเข้ารหัสเหล่านี้ ภาษาอังกฤษและภาษาจีนสามารถประมวลผลได้เหมือนกัน วิธีแยกแยะการเข้ารหัสภาษาจีนคือบิตสูงสุดของไบต์สูงไม่ใช่ 0 ตามที่โปรแกรมเมอร์เรียกมันว่า GB2312, GBK ถึง GB18030 ทั้งหมดอยู่ในชุดอักขระแบบไบต์คู่ (DBCS)
รหัสภายในเริ่มต้นของ Windows จีนบางรุ่นยังคงเป็น GBK ซึ่งสามารถอัปเกรดเป็น GB18030 ได้ผ่านแพ็คเกจอัปเกรด GB18030 อย่างไรก็ตาม อักขระที่เพิ่มโดย GB18030 เมื่อเทียบกับ GBK นั้นเป็นเรื่องยากสำหรับคนทั่วไปที่จะใช้ GBK เพื่ออ้างถึงรหัสภายในของ Windows ของจีน
นี่คือรายละเอียดเพิ่มเติมบางส่วน:
ข้อความต้นฉบับของ GB2312 ยังคงเป็นรหัสพื้นที่ จากรหัสพื้นที่ถึงรหัสภายใน จะต้องเพิ่ม A0 ในไบต์สูงและไบต์ต่ำตามลำดับ
ใน DBCS รูปแบบการจัดเก็บข้อมูลของโค้ดภายใน GB จะเป็น big endian เสมอ นั่นคือบิตที่มีลำดับสูงมาก่อน
บิตสูงสุดของสองไบต์ของ GB2312 คือ 1 ทั้งคู่ แต่มีเพียง 128*128=16384 จุดโค้ดที่ตรงตามเงื่อนไขนี้ ดังนั้น บิตสูงสุดของไบต์ต่ำของ GBK และ GB18030 อาจไม่ใช่ 1 อย่างไรก็ตาม สิ่งนี้จะไม่ส่งผลกระทบต่อการแยกวิเคราะห์สตรีมอักขระ DBCS: เมื่ออ่านสตรีมอักขระ DBCS ตราบใดที่พบไบต์ที่มีบิตสูงเป็น 1 สองไบต์ถัดไปสามารถเข้ารหัสเป็นไบต์คู่ได้ โดยไม่คำนึงถึง ไบต์ต่ำ ตำแหน่งสูงคืออะไร
2. ยูนิโค้ด, UCS และ UTF
ตามที่กล่าวไว้ข้างต้น วิธีการเข้ารหัสจาก ASCII, GB2312, GBK ถึง GB18030 นั้นเข้ากันได้แบบย้อนหลัง Unicode เข้ากันได้กับ ASCII เท่านั้น (หรือแม่นยำยิ่งขึ้นเข้ากันได้กับ ISO-8859-1) และเข้ากันไม่ได้กับรหัส GB ตัวอย่างเช่น การเข้ารหัส Unicode ของอักขระ "汉" คือ 6C49 ในขณะที่รหัส GB คือ BABA
Unicode เป็นวิธีการเข้ารหัสอักขระด้วย แต่ได้รับการออกแบบโดยองค์กรระหว่างประเทศและสามารถรองรับรูปแบบการเข้ารหัสสำหรับทุกภาษาทั่วโลก ชื่อทางวิทยาศาสตร์ของ Unicode คือ "Universal Multiple-Octet Coded Character Set" หรือเรียกสั้น ๆ ว่า UCS UCS สามารถมองได้ว่าเป็นตัวย่อของ "ชุดอักขระ Unicode"
ตามวิกิพีเดีย ( http://zh.wikipedia.org/wiki/ ): ในอดีตมีสององค์กรที่พยายามออกแบบ Unicode อย่างเป็นอิสระ ได้แก่ องค์การระหว่างประเทศเพื่อการมาตรฐาน (ISO) และสมาคมผู้ผลิตซอฟต์แวร์ (unicode องค์กร) ISO พัฒนาโครงการ ISO 10646 และ Unicode Consortium ได้พัฒนาโครงการ Unicode
ประมาณปี 1991 ทั้งสองฝ่ายตระหนักดีว่าโลกไม่จำเป็นต้องมีชุดอักขระที่เข้ากันไม่ได้สองชุด ดังนั้นพวกเขาจึงเริ่มรวมงานของทั้งสองฝ่ายและทำงานร่วมกันเพื่อสร้างรายการรหัสเดียว เริ่มต้นจาก Unicode2.0 โปรเจ็กต์ Unicode จะใช้ฟอนต์และฟอนต์เดียวกันกับ ISO 10646-1
ทั้งสองโครงการยังคงมีอยู่และเผยแพร่มาตรฐานของตนเองอย่างเป็นอิสระ Unicode Consortium เวอร์ชันล่าสุดคือ Unicode 4.1.0 ในปี 2548 มาตรฐาน ISO ล่าสุดคือ 10646-3:2003
UCS ระบุวิธีการใช้หลายไบต์เพื่อแสดงข้อความต่างๆ วิธีส่งการเข้ารหัสเหล่านี้กำหนดโดยข้อกำหนด UTF (UCS Transformation Format) ข้อกำหนดทั่วไปของ UTF ได้แก่ UTF-8, UTF-7 และ UTF-16
RFC2781 และ RFC3629 ของ IETF อธิบายวิธีการเข้ารหัสของ UTF-16 และ UTF-8 อย่างชัดเจน ชัดเจน และเข้มงวดในรูปแบบ RFC ที่สอดคล้องกัน ฉันลืมไปเสมอว่า IETF เป็นตัวย่อของ Internet Engineering Task Force อย่างไรก็ตาม RFC ที่ดูแลโดย IETF นั้นเป็นพื้นฐานสำหรับข้อกำหนดทั้งหมดบนอินเทอร์เน็ต
3. UCS-2, UCS-4, BMP
UCS มีสองรูปแบบ: UCS-2 และ UCS-4 ตามชื่อที่แนะนำ UCS-2 ถูกเข้ารหัสด้วยสองไบต์ และ UCS-4 ถูกเข้ารหัสด้วย 4 ไบต์ (จริงๆ แล้วใช้เพียง 31 บิตเท่านั้น บิตสูงสุดต้องเป็น 0) มาเล่นเกมคณิตศาสตร์ง่ายๆ กัน:
UCS-2 มีจุดโค้ด 2^16=65536 จุด และ UCS-4 มีจุดโค้ด 2^31=2147483648
UCS-4 แบ่งออกเป็น 2^7=128 กลุ่มตามไบต์สูงสุดโดยบิตสูงสุดคือ 0 แต่ละกลุ่มแบ่งออกเป็น 256 ระนาบตามไบต์สูงสุดถัดไป แต่ละระนาบแบ่งออกเป็น 256 แถวตามไบต์ที่สาม และแต่ละแถวมี 256 เซลล์ แน่นอนว่า เซลล์ในแถวเดียวกันต่างกันเพียงไบต์สุดท้ายเท่านั้น และเซลล์ที่เหลือก็เหมือนกัน
ระนาบ 0 ของกลุ่ม 0 เรียกว่า Basic Multilingual Plane หรือ BMP หรือใน UCS-4 บิตโค้ดที่มีสองไบต์บนเป็น 0 เรียกว่า BMP
ได้รับ UCS-2 โดยการลบศูนย์ไบต์สองตัวแรกของ BMP ของ UCS-4 เพิ่มศูนย์ไบต์สองไบต์หน้า UCS-2 สองไบต์เพื่อรับ BMP ของ UCS-4 ไม่มีการจัดสรรอักขระภายนอก BMP ในข้อกำหนด UCS-4 ปัจจุบัน
4. การเข้ารหัส UTF UTF-8 เข้ารหัส UCS ในหน่วย 8 บิต การเข้ารหัสจาก UCS-2 ถึง UTF-8 เป็นดังนี้:
การเข้ารหัส UCS-2 (เลขฐานสิบหก) สตรีมไบต์ UTF-8 (ไบนารี)
0000-007F 0xxxxxxx
0080-07FF 110xxxx 10xxxxxx
0800 - FFFF 1110xxxx 10xxxxxx 10xxxxxx
ตัวอย่างเช่น การเข้ารหัส Unicode ของอักขระ "ภาษาจีน" คือ 6C49 6C49 อยู่ระหว่าง 0800-FFFF ดังนั้นคุณต้องใช้เทมเพลตขนาด 3 ไบต์: 1110xxxx 10xxxxxx 10xxxxxx การเขียน 6C49 ในไบนารี่คือ: 0110 110001 001001 การใช้บิตสตรีมนี้เพื่อแทนที่ x ในเทมเพลต เราจะได้: 11100110 10110001 10001001 ซึ่งก็คือ E6 B1 89
ผู้อ่านสามารถใช้ Notepad เพื่อทดสอบว่าการเข้ารหัสของเราถูกต้องหรือไม่
UTF-16 เข้ารหัส UCS ในหน่วย 16 บิต สำหรับรหัส UCS ที่น้อยกว่า 0x10000 การเข้ารหัส UTF-16 จะเท่ากับจำนวนเต็ม 16 บิตที่ไม่ได้ลงนามซึ่งสอดคล้องกับรหัส UCS สำหรับรหัส UCS ไม่น้อยกว่า 0x10000 จะมีการกำหนดอัลกอริทึม อย่างไรก็ตาม เนื่องจาก BMP ของ UCS2 หรือ UCS4 ที่ใช้งานจริงจะต้องน้อยกว่า 0x10000 ในตอนนี้จึงถือว่า UTF-16 และ UCS-2 โดยพื้นฐานแล้วเหมือนกัน อย่างไรก็ตาม UCS-2 เป็นเพียงรูปแบบการเข้ารหัส และใช้ UTF-16 สำหรับการส่งข้อมูลจริง ดังนั้นจึงจำเป็นต้องพิจารณาปัญหาลำดับไบต์ด้วย
5. ลำดับไบต์ UTF และ BOM
UTF-8 ใช้ไบต์เป็นหน่วยการเข้ารหัส และไม่มีปัญหาลำดับไบต์ UTF-16 ใช้ 2 ไบต์เป็นหน่วยการเข้ารหัส ก่อนที่จะตีความข้อความ UTF-16 คุณต้องเข้าใจลำดับไบต์ของแต่ละหน่วยการเข้ารหัสก่อน ตัวอย่างเช่น การเข้ารหัส Unicode ของ "Kui" ที่ได้รับคือ 594E และการเข้ารหัส Unicode ของ "B" คือ 4E59 หากเราได้รับสตรีม UTF-16 ไบต์ "594E" นี่คือ "Ku" หรือ "B"
วิธีที่แนะนำในการทำเครื่องหมายลำดับไบต์ในข้อกำหนด Unicode คือ BOM BOM ไม่ใช่รายการ BOM ของ "Bill Of Material" แต่เป็น Byte Order Mark BOM เป็นแนวคิดที่ฉลาดนิดหน่อย:
มีอักขระชื่อ "ZERO WIDTH NO-BREAK SPACE" ในการเข้ารหัส UCS และการเข้ารหัสคือ FEFF FFFE เป็นอักขระที่ไม่มีอยู่ใน UCS ดังนั้นจึงไม่ควรปรากฏในการส่งสัญญาณจริง ข้อกำหนด UCS แนะนำให้เราส่งอักขระ "ZERO WIDTH NO-BREAK SPACE" ก่อนที่จะส่งสตรีมไบต์
ด้วยวิธีนี้ หากผู้รับได้รับ FEFF ก็แสดงว่าสตรีมไบต์นั้นเป็น Big-Endian หากได้รับ FFFE ก็แสดงว่าสตรีมไบต์นั้นเป็น Little-Endian ดังนั้นอักขระ "ZERO WIDTH NO-BREAK SPACE" จึงถูกเรียกว่า BOM
UTF-8 ไม่จำเป็นต้องมี BOM เพื่อระบุลำดับไบต์ แต่สามารถใช้ BOM เพื่อระบุวิธีการเข้ารหัสได้ การเข้ารหัส UTF-8 ของอักขระ "ZERO WIDTH NO-BREAK SPACE" คือ EF BB BF (ผู้อ่านสามารถตรวจสอบได้โดยใช้วิธีการเข้ารหัสที่เราแนะนำไปก่อนหน้านี้) ดังนั้นหากผู้รับได้รับสตรีมไบต์ที่เริ่มต้นด้วย EF BB BF ก็จะรู้ว่ามีการเข้ารหัส UTF-8
Windows ใช้ BOM เพื่อทำเครื่องหมายการเข้ารหัสไฟล์ข้อความ
6. เอกสารอ้างอิงเพิ่มเติม เอกสารอ้างอิงหลักสำหรับบทความนี้คือ "ภาพรวมโดยย่อของ ISO-IEC 10646 และ Unicode" ( http://www.nada.kth.se/i18n/ucs/unicode-iso10646-oview.html )
ฉันยังพบข้อมูลสองชิ้นที่ดูดี แต่เนื่องจากฉันมีคำตอบสำหรับคำถามเริ่มแรกแล้ว ฉันจึงไม่ได้อ่านข้อมูลเหล่านั้น:
"การทำความเข้าใจ Unicode การแนะนำทั่วไปเกี่ยวกับ Unicode Standard" ( http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&item_id=IWS-Chapter04a )
"พื้นฐานการเข้ารหัสชุดอักขระ ทำความเข้าใจการเข้ารหัสชุดอักขระและการเข้ารหัสแบบเดิม" ( http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&item_id=IWS-Chapter03 )
ฉันได้เขียนแพ็คเกจซอฟต์แวร์สำหรับการแปลง UTF-8, UCS-2 และ GBK ไปและกลับระหว่างกัน รวมถึงเวอร์ชันที่ใช้ Windows API และเวอร์ชันที่ไม่ได้ใช้ Windows API ถ้าฉันมีเวลาว่างในอนาคต ฉันจะจัดเรียงมันและนำไปไว้ที่หน้าแรกส่วนตัวของฉัน ( http://fmddlmyy.home4u.china.com )
ฉันเริ่มเขียนบทความนี้หลังจากคิดทบทวนประเด็นทั้งหมดแล้ว ฉันคิดว่าจะจบได้ในอีกไม่นาน โดยไม่คาดคิด การพิจารณาถ้อยคำและตรวจสอบรายละเอียดใช้เวลานานมาก โดยไม่คาดคิด ฉันเขียนไว้ตั้งแต่ 13.30 น. ถึง 9.00 น. ในช่วงบ่าย หวังว่าผู้อ่านบางคนจะได้รับประโยชน์จากมัน
-
#ภูมิภาคสุดท้าย