นั่นเป็นผลมาจากตัวละครเหล่านั้นมีลำดับการเรียงแบบเดียวกัน
คุณจะสังเกตได้ว่า
sort -u << EOF
■
⅕
⅖
⅗
EOF
ส่งคืนบรรทัดเดียวเท่านั้น
หรือว่า:
expr ■ = ⅕
ผลตอบแทนจริง (ตามที่ต้องการโดย POSIX)
โลแคลส่วนใหญ่ที่มาพร้อมกับระบบ GNU มีจำนวนอักขระ (และลำดับของอักขระ (เรียงลำดับการเรียง)) ที่มีลำดับการเรียงแบบเดียวกัน ในกรณีของ■⅕⅖⅗อันนั้นเป็นเพราะลำดับไม่ได้ถูกกำหนดไว้และตัวละครที่ไม่ได้กำหนดลำดับท้ายจะมีลำดับการเรียงลำดับเดียวกันในระบบ GNU มีตัวละครที่ถูกกำหนดไว้อย่างชัดเจนว่ามีลำดับการจัดเรียงแบบเดียวกันเช่น Ș และ though (แม้ว่าจะไม่มีตรรกะจริงหรือความแน่นอนในการเรียงลำดับเหมือนกัน)
นั่นคือที่มาของพฤติกรรมที่น่าแปลกใจและปลอม ฉันได้หยิบยกประเด็นปัญหาขึ้นมาเมื่อเร็ว ๆ นี้ในกลุ่มจดหมายของ Austin (ส่วนหลัง POSIX และ Single UNIX Specification) รายชื่อผู้รับจดหมายและการอภิปรายยังคงดำเนินต่อไปในปี 2558-2558
ในกรณีนี้ไม่ว่า[y]
จะตรงกับx
ที่x
และy
เรียงลำดับเดียวกันไม่ชัดเจนสำหรับฉัน แต่เนื่องจากการแสดงออกของวงเล็บปีกกามีความหมายเพื่อให้ตรงกับองค์ประกอบเรียงที่บ่งบอกว่าbash
พฤติกรรมที่คาดหวัง
ในกรณีใด ๆ ผมคิดว่า[⅕-⅕]
หรืออย่างน้อยก็ควรจะตรงกับ[⅕-⅖]
■
คุณจะสังเกตเห็นว่าเครื่องมือต่าง ๆ ทำงานแตกต่างกัน ksh93 มีพฤติกรรมเช่นbash
GNU grep
หรือsed
ไม่ กระสุนอื่น ๆ บางตัวมีพฤติกรรมแตกต่างกันyash
ไป
เพื่อให้มีพฤติกรรมที่สอดคล้องกันคุณต้องมีสถานที่ที่อักขระทุกตัวเรียงลำดับ โลแคล C เป็นแบบทั่วไป อย่างไรก็ตามชุดอักขระในโลแคล C บนระบบส่วนใหญ่คือ ASCII บนระบบ GNU โดยทั่วไปคุณสามารถเข้าถึงC.UTF-8
โลแคลที่สามารถใช้แทนการทำงานกับอักขระ UTF-8 ได้
ดังนั้น:
(export LC_ALL=C.UTF-8; [[ ■ = [⅕⅖⅗] ]])
หรือเทียบเท่ามาตรฐาน:
(export LC_ALL=C.UTF-8
case ■ in ([⅕⅖⅗]) true;; (*) false; esac)
ควรกลับเท็จ
อีกทางเลือกหนึ่งคือการตั้งค่าLC_COLLATE
เป็น C เท่านั้นซึ่งจะทำงานบนระบบ GNU แต่ไม่จำเป็นต้องอยู่ที่ตัวอื่นซึ่งมันอาจล้มเหลวในการระบุลำดับการเรียงของอักขระแบบหลายไบต์
บทเรียนหนึ่งของสิ่งนั้นคือความเท่าเทียมกันนั้นไม่ได้เป็นความคิดที่ชัดเจนอย่างที่ใคร ๆ คาดหวังเมื่อมันมาถึงการเปรียบเทียบสตริง ความเท่าเทียมกันอาจหมายถึงจากเข้มงวดที่สุดถึงเข้มงวดน้อยที่สุด
- จำนวนไบต์เท่ากันและองค์ประกอบไบต์ทั้งหมดมีค่าเท่ากัน
- จำนวนอักขระที่เท่ากันและอักขระทั้งหมดเหมือนกัน (ตัวอย่างเช่นอ้างถึง codepoint เดียวกันในชุดอักขระปัจจุบัน)
- สตริงทั้งสองมีลำดับการเรียงลำดับเหมือนกันตามอัลกอริทึมการเปรียบเทียบของโลแคล (นั่นคือ <b หรือ b> a ไม่เป็นจริง)
ตอนนี้สำหรับ 2 หรือ 3 ที่ถือว่าทั้งสองสตริงมีอักขระที่ถูกต้อง ใน UTF-8 และการเข้ารหัสอื่น ๆ บางลำดับของไบต์ไม่เกิดอักขระที่ถูกต้อง
1 และ 2 ไม่จำเป็นต้องเทียบเท่าเนื่องจากนั้นหรือเนื่องจากอักขระบางตัวอาจมีการเข้ารหัสที่เป็นไปได้มากกว่าหนึ่งรายการ โดยทั่วไปแล้วเป็นกรณีของการเข้ารหัส stateful เช่น ISO-2022-JP ซึ่งA
สามารถแสดงเป็น41
หรือ1b 28 42 41
( 1b 28 42
เป็นลำดับเพื่อสลับไปยัง ASCII และคุณสามารถแทรกได้มากเท่าที่คุณต้องการ แต่ก็ไม่ได้สร้างความแตกต่าง) จะไม่คาดหวังว่าการเข้ารหัสประเภทนั้นจะยังคงถูกใช้งานอยู่และเครื่องมือของ GNU อย่างน้อยโดยทั่วไปจะไม่ทำงานอย่างถูกต้องกับมัน
นอกจากนี้ระวังว่ายูทิลิตี้ที่ไม่ใช่ GNU ส่วนใหญ่ไม่สามารถจัดการกับค่า 0 ไบต์ (อักขระ NUL ใน ASCII)
ซึ่งในบรรดาคำจำกัดความถูกนำมาใช้ขึ้นอยู่กับสาธารณูปโภคและยูทิลิตี้การดำเนินงานหรือรุ่น POSIX ไม่ชัดเจน 100% ในโลแคล C ทั้ง 3 รายการเทียบเท่ากัน ด้านนอกของ YMMV นั้น