การเรียงลำดับสตริงของ Linux เป็นอย่างไร

การแนะนำ

ทุกอย่างเริ่มต้นด้วยสคริปต์สั้นๆ ที่ควรรวมข้อมูลที่อยู่เข้าด้วยกัน อีเมล พนักงานที่ได้รับจากรายชื่อผู้ใช้ Mailing List โดยมีตำแหน่งพนักงานที่ได้รับจากฐานข้อมูลแผนกทรัพยากรบุคคล ทั้งสองรายการถูกส่งออกไปยังไฟล์ข้อความ Unicode UTF-8 และบันทึกด้วยการลงท้ายบรรทัด Unix

เนื้อหา เมล.txt

Иванов Андрей;[email protected]

เนื้อหา buhg.txt

Иванова Алла;маляр
Ёлкина Элла;крановщица
Иванов Андрей;слесарь
Абаканов Михаил;маляр

หากต้องการรวมไฟล์จะถูกจัดเรียงตามคำสั่ง Unix ประเภท และส่งไปยังอินพุตของโปรแกรม Unix ร่วมซึ่งล้มเหลวโดยไม่คาดคิดโดยมีข้อผิดพลาด:

$> sort buhg.txt > buhg.srt
$> sort mail.txt > mail.srt
$> join buhg.srt mail.srt > result
join: buhg.srt:4: is not sorted: Иванов Андрей;слесарь

การดูผลการจัดเรียงด้วยตาเปล่าพบว่าโดยทั่วไปการเรียงลำดับนั้นถูกต้อง แต่ในกรณีของความบังเอิญของนามสกุลชายและหญิง นามสกุล เพศหญิง มาก่อนเพศชาย:

$> sort buhg.txt
Абаканов Михаил;маляр
Ёлкина Элла;крановщица
Иванова Алла;маляр
Иванов Андрей;слесарь

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

เอาเป็นว่าพักไว้ก่อนแล้วกัน ร่วม และมุ่งเน้นไปที่ ประเภท. เรามาลองแก้ปัญหาโดยใช้การจิ้มทางวิทยาศาสตร์กัน ก่อนอื่นเรามาเปลี่ยนสถานที่จาก en_US บน ru_ru. หากต้องการเรียงลำดับ ก็เพียงพอที่จะตั้งค่าตัวแปรสภาพแวดล้อม LC_COLLATEแต่เราจะไม่เสียเวลากับเรื่องเล็ก ๆ น้อย ๆ :

$> LANG=ru_RU.UTF-8 sort buhg.txt
Абаканов Михаил;маляр
Ёлкина Элла;крановщица
Иванова Алла;маляр
Иванов Андрей;слесарь

ไม่มีอะไรเปลี่ยนแปลง

มาลองเข้ารหัสไฟล์ใหม่เป็นการเข้ารหัสแบบไบต์เดียว:

$> iconv -f UTF-8 -t KOI8-R buhg.txt 
 | LANG=ru_RU.KOI8-R sort 
 | iconv -f KOI8-R -t UTF8

อีกครั้งไม่มีอะไรเปลี่ยนแปลง

คุณไม่สามารถทำอะไรได้ คุณจะต้องค้นหาวิธีแก้ปัญหาบนอินเทอร์เน็ต ไม่มีอะไรโดยตรงเกี่ยวกับนามสกุลของรัสเซีย แต่มีคำถามเกี่ยวกับการเรียงลำดับที่แปลกประหลาดอื่น ๆ ตัวอย่างเช่น นี่คือปัญหา: การเรียงลำดับ Unix ถือว่าอักขระ '-' (เส้นประ) มองไม่เห็น. กล่าวโดยย่อคือ สตริง "ab", "aa", "ac" จะถูกจัดเรียงเป็น "aa", "ab", "ac"

คำตอบนั้นเป็นมาตรฐานทุกที่: ใช้ภาษาโปรแกรมเมอร์ "C" และคุณจะมีความสุข มาลองกัน:

$> LANG=C sort buhg.txt
Ёлкина Элла;крановщица
Абаканов Михаил;маляр
Иванов Андрей;слесарь
Иванова Алла;адвокат

มีบางอย่างเปลี่ยนไป พวกอิวานอฟเข้าแถวตามลำดับที่ถูกต้องแม้ว่าโยลคินาจะหลุดไปที่ไหนสักแห่งก็ตาม กลับไปสู่ปัญหาเดิม:

$> LANG=C sort buhg.txt > buhg.srt
$> LANG=C sort mail.txt > mail.srt
$> LANG=C join buhg.srt mail.srt > result

มันทำงานได้โดยไม่มีข้อผิดพลาดตามที่อินเทอร์เน็ตสัญญาไว้ และสิ่งนี้แม้ Yolkina จะอยู่ในบรรทัดแรกก็ตาม

ดูเหมือนว่าปัญหาจะได้รับการแก้ไขแล้ว แต่ในกรณีนี้ให้ลองเข้ารหัสภาษารัสเซียอื่น - Windows CP1251:

$> iconv -f UTF-8 -t CP1251 buhg.txt 
 | LANG=ru_RU.CP1251 sort 
 | iconv -f CP1251 -t UTF8 

ผลการเรียงลำดับจะตรงกับสถานที่อย่างผิดปกติ "C"และตัวอย่างทั้งหมดจึงทำงานโดยไม่มีข้อผิดพลาด เวทย์มนต์บางชนิด

ฉันไม่ชอบเวทย์มนต์ในการเขียนโปรแกรมเพราะมันมักจะปกปิดข้อผิดพลาด เราจะต้องพิจารณาอย่างจริงจังว่ามันทำงานอย่างไร ประเภท และมันส่งผลกระทบอะไร? LC_COLLATE .

ในตอนท้ายฉันจะพยายามตอบคำถาม:

  • เหตุใดนามสกุลหญิงจึงเรียงลำดับไม่ถูกต้อง?
  • ทำไม LANG=ru_RU.CP1251 กลับกลายเป็นว่าเทียบเท่ากัน แลง=ซี
  • ทำไมทำ ประเภท и ร่วม แนวคิดที่แตกต่างเกี่ยวกับลำดับของสตริงที่เรียงลำดับ
  • เหตุใดจึงมีข้อผิดพลาดในตัวอย่างทั้งหมดของฉัน
  • ในที่สุดก็มีวิธีจัดเรียงสตริงตามที่คุณต้องการ

การเรียงลำดับใน Unicode

จุดแรกจะเป็นรายงานทางเทคนิคฉบับที่ 10 ที่ได้รับสิทธิ อัลกอริธึมการจัดเรียง Unicode ออนไลน์ ยูนิโค้ด.org. รายงานประกอบด้วยรายละเอียดทางเทคนิคมากมาย ดังนั้นให้ฉันสรุปแนวคิดหลักโดยย่อ

การตรวจทาน — สตริง "การเปรียบเทียบ" เป็นพื้นฐานของอัลกอริธึมการเรียงลำดับ อัลกอริธึมอาจแตกต่างกัน ("bubble", "merge", "fast") แต่ทั้งหมดจะใช้การเปรียบเทียบคู่ของสตริงเพื่อกำหนดลำดับที่ปรากฏ

การเรียงลำดับสตริงในภาษาธรรมชาติเป็นปัญหาที่ค่อนข้างซับซ้อน แม้ในการเข้ารหัสไบต์เดียวที่ง่ายที่สุดลำดับของตัวอักษรในตัวอักษรแม้จะแตกต่างจากตัวอักษรละตินภาษาอังกฤษในทางใดทางหนึ่ง แต่ก็จะไม่ตรงกับลำดับของค่าตัวเลขที่เข้ารหัสตัวอักษรเหล่านี้อีกต่อไป ดังนั้นในอักษรเยอรมันก็คือตัวอักษร Ö ยืนอยู่ระหว่าง О и Pและในการเข้ารหัส CP850 เธออยู่ระหว่างนั้น ÿ и Ü.

คุณสามารถลองสรุปจากการเข้ารหัสเฉพาะ และพิจารณาตัวอักษร "ในอุดมคติ" ที่จัดเรียงตามลำดับบางอย่าง เช่นเดียวกับที่ทำใน Unicode การเข้ารหัส UTF8, UTF16 หรือหนึ่งไบต์ KOI8-ร (หากจำเป็นต้องใช้ชุดย่อยของ Unicode ที่จำกัด) จะให้การแสดงตัวเลขของตัวอักษรที่แตกต่างกัน แต่จะอ้างอิงถึงองค์ประกอบเดียวกันของตารางฐาน

ปรากฎว่าแม้ว่าเราจะสร้างตารางสัญลักษณ์ตั้งแต่เริ่มต้น เราก็จะไม่สามารถกำหนดลำดับสัญลักษณ์สากลให้กับตารางได้ ในตัวอักษรประจำชาติต่างๆ ที่ใช้ตัวอักษรเดียวกัน ลำดับของตัวอักษรเหล่านี้อาจแตกต่างกัน ตัวอย่างเช่นในภาษาฝรั่งเศส Æ จะถือเป็นการมัดและจัดเรียงเป็นสตริง AE. ในภาษานอร์เวย์ Æ จะเป็นจดหมายแยกต่างหากซึ่งอยู่ด้านหลัง Z. โดยวิธีการนอกเหนือจากการมัดเช่น Æ มีตัวอักษรเขียนด้วยสัญลักษณ์หลายตัว ดังนั้นในอักษรเช็กจึงมีตัวอักษรตัวหนึ่ง Chซึ่งอยู่ระหว่าง H и I.

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

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

จากคุณสมบัติที่กล่าวข้างต้น ข้อกำหนดพื้นฐานสำหรับการเปรียบเทียบสตริงตามตาราง Unicode ได้รับการกำหนด:

  • การเปรียบเทียบสตริงไม่ได้ขึ้นอยู่กับตำแหน่งของอักขระในตารางโค้ด
  • ลำดับของอักขระที่สร้างอักขระตัวเดียวจะลดลงเป็นรูปแบบมาตรฐาน (A + วงกลมบนก็เหมือนเดิม Å);
  • เมื่อเปรียบเทียบสตริง อักขระจะได้รับการพิจารณาในบริบทของสตริง และหากจำเป็น จะรวมกับเพื่อนบ้านเป็นหน่วยการเปรียบเทียบเดียว (Ch ในภาษาเช็ก) หรือแบ่งออกเป็นหลาย ๆ (Æ ในฝรั่งเศส);
  • คุณสมบัติประจำชาติทั้งหมด (ตัวอักษร ตัวพิมพ์ใหญ่/ตัวพิมพ์เล็ก เครื่องหมายวรรคตอน ลำดับการเขียน) จะต้องได้รับการกำหนดค่าตามการกำหนดลำดับด้วยตนเอง (อีโมจิ)
  • การเปรียบเทียบมีความสำคัญไม่เพียงแต่สำหรับการเรียงลำดับเท่านั้น แต่ยังมีความสำคัญในที่อื่นๆ ด้วย เช่น การระบุช่วงแถว (แทนที่ {A... z} ใน ทุบตี);
  • การเปรียบเทียบควรทำอย่างรวดเร็วพอสมควร

นอกจากนี้ ผู้เขียนรายงานยังได้กำหนดคุณสมบัติการเปรียบเทียบที่นักพัฒนาอัลกอริทึมไม่ควรยึดถือ:

  • อัลกอริธึมการเปรียบเทียบไม่ควรต้องมีชุดอักขระแยกต่างหากสำหรับแต่ละภาษา (ภาษารัสเซียและยูเครนใช้อักขระซีริลลิกส่วนใหญ่ร่วมกัน)
  • การเปรียบเทียบไม่ควรขึ้นอยู่กับลำดับอักขระในตาราง Unicode
  • น้ำหนักสตริงไม่ควรเป็นแอตทริบิวต์ของสตริง เนื่องจากสตริงเดียวกันในบริบททางวัฒนธรรมที่แตกต่างกันสามารถมีน้ำหนักต่างกันได้
  • น้ำหนักแถวสามารถเปลี่ยนแปลงได้เมื่อรวมหรือแยก (จาก x < y มันไม่เป็นไปตามนั้น xz < yz);
  • สตริงที่แตกต่างกันซึ่งมีน้ำหนักเท่ากันจะถือว่าเท่ากันจากมุมมองของอัลกอริธึมการเรียงลำดับ การแนะนำลำดับเพิ่มเติมของสตริงดังกล่าวเป็นไปได้ แต่อาจทำให้ประสิทธิภาพลดลง
  • ในระหว่างการเรียงลำดับซ้ำ แถวที่มีน้ำหนักเท่ากันอาจถูกสลับ ความคงทนเป็นคุณสมบัติของอัลกอริธึมการเรียงลำดับเฉพาะ และไม่ใช่คุณสมบัติของอัลกอริธึมการเปรียบเทียบสตริง (ดูย่อหน้าก่อนหน้า)
  • กฎการเรียงลำดับอาจเปลี่ยนแปลงไปตามกาลเวลาตามประเพณีทางวัฒนธรรมที่ได้รับการขัดเกลา/เปลี่ยนแปลง

มีการระบุไว้ด้วยว่าอัลกอริธึมการเปรียบเทียบไม่รู้อะไรเลยเกี่ยวกับความหมายของสตริงที่กำลังประมวลผล ดังนั้น ไม่ควรเปรียบเทียบสตริงที่มีเฉพาะตัวเลขเป็นตัวเลข และในรายการชื่อภาษาอังกฤษ บทความ (บีเทิลส์, เดอะ).

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

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

ในการใช้งานอัลกอริธึมที่แตกต่างกันสำหรับประเพณีประจำชาติที่แตกต่างกันค่าของสัมประสิทธิ์อาจแตกต่างกัน แต่มาตรฐาน Unicode จะมีตารางน้ำหนักพื้นฐาน - "ตารางองค์ประกอบการจัดเรียง Unicode เริ่มต้น" (ดูเซท). ฉันอยากจะทราบว่าการตั้งค่าตัวแปร LC_COLLATE จริงๆ แล้วเป็นการบ่งชี้การเลือกตารางน้ำหนักในฟังก์ชันการเปรียบเทียบสตริง

ค่าสัมประสิทธิ์การถ่วงน้ำหนัก ดูเซท จัดดังนี้:

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

การเปรียบเทียบเกิดขึ้นในหลายรอบ: ขั้นแรก เปรียบเทียบค่าสัมประสิทธิ์ของระดับแรก หากน้ำหนักตรงกันจะทำการเปรียบเทียบซ้ำกับน้ำหนักระดับที่สอง บางทีอาจเป็นหนึ่งในสามและสี่

การเปรียบเทียบจะสิ้นสุดเมื่อแถวมีหน่วยการเปรียบเทียบที่ตรงกันซึ่งมีน้ำหนักต่างกัน แถวที่มีน้ำหนักเท่ากันทั้งสี่ระดับจะถือว่าเท่ากัน

อัลกอริทึมนี้ (พร้อมรายละเอียดทางเทคนิคเพิ่มเติมมากมาย) ทำให้ชื่อรายงานหมายเลข 10 - "อัลกอริธึมการจัดเรียง Unicode" (UCA).

นี่คือจุดที่พฤติกรรมการเรียงลำดับจากตัวอย่างของเราชัดเจนขึ้นเล็กน้อย คงจะดีถ้าเปรียบเทียบกับมาตรฐาน Unicode

เพื่อทดสอบการใช้งาน UCA มีความพิเศษอยู่ ทดสอบ, โดยใช้ ไฟล์น้ำหนัก, การดำเนินการ ดูเซท. คุณจะพบเรื่องตลกทุกประเภทได้ในไฟล์ตาชั่ง เช่นมีลำดับไพ่นกกระจอกและโดมิโนยุโรปรวมทั้งลำดับไพ่ในสำรับไพ่ (สัญลักษณ์ 1F000 และต่อไป). ชุดไพ่จะถูกวางตามกฎของบริดจ์ - PCBT และไพ่ในชุดจะอยู่ตามลำดับ T, 2,3, XNUMX... K

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

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

Абаканов Михаил;маляр
Ёлкина Элла;крановщица
Иванов Андрей;слесарь
Иванова Алла;адвокат

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

Unicode ช่วยเราได้ แต่มองหาสาเหตุของพฤติกรรมแปลกๆ ประเภท в ลินุกซ์ จะต้องไปที่อื่น

การเรียงลำดับใน glibc

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

$ sort --debug buhg.txt > buhg.srt
sort: using ‘en_US.UTF8’ sorting rules

การเปรียบเทียบสตริงดำเนินการโดยใช้ฟังก์ชันมาตรฐาน หยุดซึ่งหมายความว่าทุกสิ่งที่น่าสนใจอยู่ในห้องสมุด glibc.

На วิกิพีเดีย โครงการ glibc ทุ่มเทให้กับการเปรียบเทียบสตริง หนึ่งย่อหน้า. จากย่อหน้านี้สามารถเข้าใจได้ว่าใน glibc การเรียงลำดับจะขึ้นอยู่กับอัลกอริทึมที่เรารู้จักอยู่แล้ว UCA (อัลกอริธึมการจัดเรียง Unicode) และ/หรือมาตรฐานที่ใกล้เคียงกัน ISO.14651 (การเรียงลำดับและเปรียบเทียบสตริงระหว่างประเทศ). ในส่วนของมาตรฐานล่าสุดก็ควรสังเกตว่าบนเว็บไซต์ Standards.iso.org ISO.14651 ประกาศอย่างเป็นทางการต่อสาธารณะ แต่ลิงก์ที่เกี่ยวข้องนำไปสู่หน้าที่ไม่มีอยู่จริง Google ส่งคืนหน้าเว็บหลายหน้าพร้อมลิงก์ไปยังเว็บไซต์อย่างเป็นทางการที่เสนอให้ซื้อสำเนาอิเล็กทรอนิกส์มาตรฐานในราคาหนึ่งร้อยยูโร แต่ในผลการค้นหาหน้าที่สามหรือสี่ก็มีลิงก์โดยตรงไปยัง รูปแบบไฟล์ PDF. โดยทั่วไปมาตรฐานแทบไม่ต่างจาก UCAแต่จะน่าเบื่อกว่าในการอ่านเนื่องจากไม่มีตัวอย่างที่ชัดเจนเกี่ยวกับคุณลักษณะประจำชาติของการเรียงลำดับสตริง

ข้อมูลที่น่าสนใจที่สุดเกี่ยวกับ วิกิพีเดีย มีลิงก์ไปยัง ติดตามข้อผิดพลาด โดยมีการอภิปรายถึงการดำเนินการเปรียบเทียบสตริงค่ะ glibc. จากการสนทนาสามารถเรียนรู้ได้ว่า glibc ใช้ในการเปรียบเทียบสตริง มาตรฐาน ISOโต๊ะส่วนตัว ตารางเทมเพลตทั่วไป (CTT) ที่อยู่ซึ่งสามารถพบได้ในแอปพลิเคชัน A มาตรฐาน ISO.14651. ระหว่างปี 2000 ถึง 2015 ตารางนี้ใน glibc ไม่มีผู้ดูแลและค่อนข้างแตกต่าง (อย่างน้อยก็ภายนอก) จากเวอร์ชันปัจจุบันของมาตรฐาน ตั้งแต่ปี 2015 ถึง 2018 มีการปรับให้เข้ากับตารางเวอร์ชันใหม่และตอนนี้คุณมีโอกาสได้พบกับตารางเวอร์ชันใหม่ในชีวิตจริง (8 CentOS) และเก่า (7 CentOS).

ตอนนี้เรามีข้อมูลทั้งหมดเกี่ยวกับอัลกอริทึมและตารางเสริมแล้ว เราก็สามารถกลับไปสู่ปัญหาเดิมและทำความเข้าใจวิธีจัดเรียงสตริงในภาษารัสเซียได้อย่างถูกต้อง

ISO 14651 / 14652

Source Code ของตารางที่เราสนใจ CTT ในการแจกแจงส่วนใหญ่ ลินุกซ์ อยู่ในไดเรกทอรี /usr/share/i18n/locales/. ตารางนั้นอยู่ในไฟล์ iso14651_t1_common. นี่คือคำสั่งไฟล์ คัดลอก iso14651_t1_common รวมอยู่ในไฟล์ iso14651_t1ซึ่งในที่สุดก็รวมอยู่ในไฟล์ระดับชาติรวมไปถึง en_US и ru_ru. ในการแจกแจงส่วนใหญ่ ลินุกซ์ ไฟล์ต้นฉบับทั้งหมดจะรวมอยู่ในการติดตั้งขั้นพื้นฐาน แต่หากไม่มีคุณจะต้องติดตั้งแพ็คเกจเพิ่มเติมจากการแจกจ่าย

โครงสร้างไฟล์ iso14651_t1 อาจดูละเอียดมาก โดยมีกฎเกณฑ์ที่ไม่ชัดเจนในการสร้างชื่อ แต่ถ้าคุณดูทุกอย่างก็ค่อนข้างง่าย โครงสร้างมีการอธิบายไว้ในมาตรฐาน ISO.14652ซึ่งสามารถดาวน์โหลดสำเนาได้จากเว็บไซต์ open-std.org. คำอธิบายอื่นของรูปแบบไฟล์สามารถอ่านได้ ข้อกำหนด POSIX จาก โอเพ่นกรุ๊ป. แทนที่จะอ่านมาตรฐาน คุณสามารถศึกษาซอร์สโค้ดของฟังก์ชันได้ collate_read в glibc/locale/programs/ld-collate.c.

โครงสร้างไฟล์มีลักษณะดังนี้:

ตามค่าเริ่มต้น อักขระจะถูกใช้เป็นอักขระหลีก และจุดสิ้นสุดของบรรทัดหลังอักขระ # คือความคิดเห็น สัญลักษณ์ทั้งสองสามารถกำหนดใหม่ได้ ซึ่งเป็นสิ่งที่ทำในตารางเวอร์ชันใหม่:

escape_char /
comment_char %

ไฟล์จะมีโทเค็นในรูปแบบ หรือ (ที่ไหน x - เลขฐานสิบหก) นี่คือการแสดงเลขฐานสิบหกของจุดโค้ด Unicode ในการเข้ารหัส ยูซีเอส-4 (UTF-32). องค์ประกอบอื่นๆ ทั้งหมดในวงเล็บมุม (รวมถึง , <2> และสิ่งที่คล้ายคลึงกัน) ถือเป็นค่าคงที่สตริงอย่างง่ายซึ่งมีความหมายเพียงเล็กน้อยนอกบริบท

เส้น LC_COLLATE บอกเราว่าถัดไปจะเริ่มต้นข้อมูลที่อธิบายการเปรียบเทียบสตริง

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

ความยาวรวมของส่วนในการแก้ไขไฟล์ปัจจุบันคือประมาณ 900 บรรทัด ฉันดึงตัวอย่างจากหลายแห่งเพื่อแสดงความเด็ดขาดของชื่อและไวยากรณ์หลายประเภท

LC_COLLATE

collating-symbol <RES-1>
collating-symbol <BLK>
collating-symbol <MIN>
collating-symbol <WIDE>
...
collating-symbol <ARABIC>
collating-symbol <ETHPC>
collating-symbol <OSMANYA>
...
collating-symbol <S1D000>..<S1D35F>
collating-symbol <SFFFF> % Guaranteed largest symbol value. Keep at end of this list
...
collating-element <U0413_0301> from "<U0413><U0301>"
collating-element <U0413_0341> from "<U0413><U0341>"

  • การเรียงสัญลักษณ์ บันทึกสตริง ออสมาเนีย ในตารางชื่อตาชั่ง
  • การเรียงสัญลักษณ์ .. ลงทะเบียนลำดับของชื่อที่ประกอบด้วยคำนำหน้า S และคำต่อท้ายตัวเลขฐานสิบหกจาก 1D000 ไปยัง 1D35F.
  • FFFF в การเรียงสัญลักษณ์ ดูเหมือนจำนวนเต็มขนาดใหญ่ที่ไม่ได้ลงนามในเลขฐานสิบหก แต่ มันเป็นเพียงชื่อที่อาจดูเหมือน
  • ชื่อ หมายถึงจุดรหัสในการเข้ารหัส ยูซีเอส-4
  • การจัดเรียงองค์ประกอบ จาก " " ลงทะเบียนชื่อใหม่สำหรับคู่ของจุด Unicode

เมื่อกำหนดชื่อของน้ำหนักแล้ว จะมีการระบุน้ำหนักจริง เนื่องจากความสัมพันธ์ที่มากกว่าน้อยกว่ามีความสำคัญในการเปรียบเทียบ น้ำหนักจึงถูกกำหนดโดยลำดับรายการอย่างง่าย ๆ ตุ้มน้ำหนักที่ "เบากว่า" จะถูกระบุไว้ก่อน จากนั้นจึงระบุตุ้มน้ำหนักที่ "หนักกว่า" ฉันขอเตือนคุณว่าอักขระ Unicode แต่ละตัวมีน้ำหนักที่แตกต่างกันสี่แบบ ที่นี่จะรวมกันเป็นลำดับเดียว ตามทฤษฎีแล้ว ชื่อเชิงสัญลักษณ์ใดๆ ก็ตามสามารถใช้ได้ในระดับใดก็ได้จากทั้งสี่ระดับ แต่ความคิดเห็นระบุว่านักพัฒนาได้แยกชื่อทางจิตใจออกเป็นระดับต่างๆ

% Symbolic weight assignments

% Third-level weight assignments
<RES-1>
<BLK>
<MIN>
<WIDE>
...
% Second-level weight assignments
<BASE>
<LOWLINE> % COMBINING LOW LINE
<PSILI> % COMBINING COMMA ABOVE
<DASIA> % COMBINING REVERSED COMMA ABOVE
...
% First-level weight assignments
<S0009> % HORIZONTAL TABULATION 
<S000A> % LINE FEED
<S000B> % VERTICAL TABULATION
...
<S0434> % CYRILLIC SMALL LETTER DE
<S0501> % CYRILLIC SMALL LETTER KOMI DE
<S0452> % CYRILLIC SMALL LETTER DJE
<S0503> % CYRILLIC SMALL LETTER KOMI DJE
<S0453> % CYRILLIC SMALL LETTER GJE
<S0499> % CYRILLIC SMALL LETTER ZE WITH DESCENDER
<S0435> % CYRILLIC SMALL LETTER IE
<S04D7> % CYRILLIC SMALL LETTER IE WITH BREVE
<S0454> % CYRILLIC SMALL LETTER UKRAINIAN IE
<S0436> % CYRILLIC SMALL LETTER ZHE

สุดท้ายนี้ตารางน้ำหนักจริง

ส่วนน้ำหนักอยู่ในบรรทัดคำหลัก สั่งซื้อ_เริ่มต้น и สั่งซื้อ_end. ตัวเลือกพิเศษ สั่งซื้อ_เริ่มต้น กำหนดว่าแถวทิศทางใดจะถูกสแกนในแต่ละระดับของการเปรียบเทียบ การตั้งค่าเริ่มต้นคือ ข้างหน้า. เนื้อความของส่วนประกอบด้วยบรรทัดที่มีรหัสสัญลักษณ์และน้ำหนักทั้งสี่ของมัน รหัสอักขระสามารถแสดงด้วยอักขระเอง จุดรหัส หรือชื่อสัญลักษณ์ที่กำหนดไว้ก่อนหน้านี้ นอกจากนี้ยังสามารถกำหนดน้ำหนักให้กับชื่อสัญลักษณ์ จุดรหัส หรือตัวสัญลักษณ์ได้ด้วย ถ้าใช้จุดโค้ดหรืออักขระ น้ำหนักจะเท่ากับค่าตัวเลขของจุดโค้ด (ตำแหน่งในตาราง Unicode) อักขระที่ไม่ได้ระบุอย่างชัดเจน (ตามที่ฉันเข้าใจ) จะถือว่าถูกกำหนดให้กับตารางโดยมีน้ำหนักหลักที่ตรงกับตำแหน่งในตาราง Unicode ค่าน้ำหนักพิเศษ ไม่สนใจ หมายความว่าสัญลักษณ์จะถูกละเว้นในระดับการเปรียบเทียบที่เหมาะสม

เพื่อสาธิตโครงสร้างของตาชั่ง ฉันเลือกชิ้นส่วนที่ค่อนข้างชัดเจนสามส่วน:

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

order_start forward;forward;forward;forward,position
<U0000> IGNORE;IGNORE;IGNORE;IGNORE % NULL (in 6429)
<U0001> IGNORE;IGNORE;IGNORE;IGNORE % START OF HEADING (in 6429)
<U0002> IGNORE;IGNORE;IGNORE;IGNORE % START OF TEXT (in 6429)
...
<U0033> <S0033>;<BASE>;<MIN>;<U0033> % DIGIT THREE
<UFF13> <S0033>;<BASE>;<WIDE>;<UFF13> % FULLWIDTH DIGIT THREE
<U2476> <S0033>;<BASE>;<COMPAT>;<U2476> % PARENTHESIZED DIGIT THREE
<U248A> <S0033>;<BASE>;<COMPAT>;<U248A> % DIGIT THREE FULL STOP
<U1D7D1> <S0033>;<BASE>;<FONT>;<U1D7D1> % MATHEMATICAL BOLD DIGIT THREE
...
<U0430> <S0430>;<BASE>;<MIN>;<U0430> % CYRILLIC SMALL LETTER A
<U0410> <S0430>;<BASE>;<CAP>;<U0410> % CYRILLIC CAPITAL LETTER A
<U04D1> <S04D1>;<BASE>;<MIN>;<U04D1> % CYRILLIC SMALL LETTER A WITH BREVE
<U0430_0306> <S04D1>;<BASE>;<MIN>;<U04D1> % CYRILLIC SMALL LETTER A WITH BREVE
...
<U0431> <S0431>;<BASE>;<MIN>;<U0431> % CYRILLIC SMALL LETTER BE
<U0411> <S0431>;<BASE>;<CAP>;<U0411> % CYRILLIC CAPITAL LETTER BE
<U0432> <S0432>;<BASE>;<MIN>;<U0432> % CYRILLIC SMALL LETTER VE
<U0412> <S0432>;<BASE>;<CAP>;<U0412> % CYRILLIC CAPITAL LETTER VE
...
order_end

ตอนนี้คุณสามารถกลับไปเรียงลำดับตัวอย่างตั้งแต่ต้นบทความได้แล้ว การซุ่มโจมตีอยู่ในส่วนนี้ของตารางน้ำหนัก:

<U0020> IGNORE;IGNORE;IGNORE;<U0020> % SPACE
<U0021> IGNORE;IGNORE;IGNORE;<U0021> % EXCLAMATION MARK
<U0022> IGNORE;IGNORE;IGNORE;<U0022> % QUOTATION MARK
...

จะเห็นได้ว่าในตารางนี้มีเครื่องหมายวรรคตอนจากตาราง ASCII (รวมถึงช่องว่าง) มักจะถูกละเลยเมื่อเปรียบเทียบสตริง ข้อยกเว้นเพียงอย่างเดียวคือบรรทัดที่ตรงกันในทุกรายการ ยกเว้นเครื่องหมายวรรคตอนที่พบในตำแหน่งที่ตรงกัน บรรทัดจากตัวอย่างของฉัน (หลังการเรียงลำดับ) สำหรับอัลกอริธึมการเปรียบเทียบมีลักษณะดังนี้:

АбакановМихаилмаляр
ЁлкинаЭллакрановщица
ИвановаАлламаляр
ИвановАндрейслесарь

เมื่อพิจารณาว่าในตารางมาตราส่วน ตัวพิมพ์ใหญ่ในภาษารัสเซียจะอยู่หลังตัวพิมพ์เล็ก (ในระดับที่สาม หนักกว่า ) การเรียงลำดับดูถูกต้องอย่างยิ่ง

เมื่อตั้งค่าตัวแปร LC_COLLATE=ค มีการโหลดตารางพิเศษที่ระบุการเปรียบเทียบแบบไบต์ต่อไบต์

static const uint32_t collseqwc[] =
{
  8, 1, 8, 0x0, 0xff,
  /* 1st-level table */
  6 * sizeof (uint32_t),
  /* 2nd-level table */
  7 * sizeof (uint32_t),
  /* 3rd-level table */
  L'x00', L'x01', L'x02', L'x03', L'x04', L'x05', L'x06', L'x07',
  L'x08', L'x09', L'x0a', L'x0b', L'x0c', L'x0d', L'x0e', L'x0f',

...
  L'xf8', L'xf9', L'xfa', L'xfb', L'xfc', L'xfd', L'xfe', L'xff'
};

เนื่องจากใน Unicode จุดโค้ด Ё มาก่อน A สตริงจึงถูกจัดเรียงตามนั้น

ข้อความและตารางไบนารี

แน่นอนว่าการเปรียบเทียบสตริงเป็นการดำเนินการทั่วไปและการแยกวิเคราะห์ตาราง CTT เป็นขั้นตอนที่ค่อนข้างมีค่าใช้จ่ายสูง เพื่อเพิ่มประสิทธิภาพการเข้าถึงตาราง ตารางจะถูกคอมไพล์เป็นรูปแบบไบนารี่ด้วยคำสั่ง localdef.

ทีม localdef ยอมรับเป็นพารามิเตอร์ไฟล์ที่มีตารางคุณลักษณะประจำชาติ (ตัวเลือก -i) ซึ่งอักขระทั้งหมดจะแสดงด้วยจุด Unicode และไฟล์การติดต่อระหว่างจุด Unicode และอักขระของการเข้ารหัสเฉพาะ (ตัวเลือก -f). จากการทำงาน ไฟล์ไบนารีจะถูกสร้างขึ้นสำหรับโลแคลด้วยชื่อที่ระบุในพารามิเตอร์สุดท้าย

glibc รองรับไฟล์ไบนารี่สองรูปแบบ: "ดั้งเดิม" และ "สมัยใหม่"

รูปแบบดั้งเดิมหมายความว่าชื่อของสถานที่คือชื่อของไดเรกทอรีย่อยใน /usr/lib/สถานที่/. ไดเร็กทอรีย่อยนี้เก็บไฟล์ไบนารี่ LC_COLLATE, LC_CTYPE, LC_TIME และอื่น ๆ ไฟล์ LC_IDENTIFICATION มีชื่อที่เป็นทางการของสถานที่ (ซึ่งอาจแตกต่างจากชื่อไดเรกทอรี) และความคิดเห็น

รูปแบบสมัยใหม่เกี่ยวข้องกับการจัดเก็บสถานที่ทั้งหมดไว้ในไฟล์เก็บถาวรเดียว /usr/lib/locale/locale-เก็บถาวรซึ่งแมปกับหน่วยความจำเสมือนของกระบวนการทั้งหมดที่ใช้ glibc. ชื่อสถานที่ในรูปแบบสมัยใหม่อยู่ภายใต้การกำหนดรูปแบบมาตรฐาน - มีเพียงตัวเลขและตัวอักษรที่ลดเป็นตัวพิมพ์เล็กเท่านั้นที่ยังคงอยู่ในชื่อการเข้ารหัส ดังนั้น ru_RU.KOI8-Rจะถูกบันทึกเป็น ru_RU.koi8r.

ไฟล์อินพุตจะถูกค้นหาในไดเร็กทอรีปัจจุบัน รวมถึงในไดเร็กทอรีด้วย /usr/share/i18n/locales/ и /usr/share/i18n/charmaps/ สำหรับไฟล์ CTT และไฟล์เข้ารหัสตามลำดับ

เช่น คำสั่ง

localedef -i ru_RU -f MAC-CYRILLIC ru_RU.MAC-CYRILLIC

จะคอมไพล์ไฟล์ /usr/share/i18n/locales/ru_RU โดยใช้ไฟล์เข้ารหัส /usr/share/i18n/charmaps/MAC-CYRILLIC.gz และบันทึกผลลัพธ์ไว้ใน /usr/lib/locale/locale-เก็บถาวร ภายใต้ชื่อ ru_RU.maccyrillic

หากคุณตั้งค่าตัวแปร LANG = en_US.UTF-8 ที่ glibc จะค้นหาไบนารีโลแคลตามลำดับไฟล์และไดเร็กทอรีต่อไปนี้:

/usr/lib/locale/locale-archive
/usr/lib/locale/en_US.UTF-8/
/usr/lib/locale/en_US/
/usr/lib/locale/enUTF-8/
/usr/lib/locale/en/

หากโลแคลเกิดขึ้นทั้งในรูปแบบดั้งเดิมและสมัยใหม่ ระบบจะให้ความสำคัญกับรูปแบบสมัยใหม่

คุณสามารถดูรายการโลแคลที่คอมไพล์แล้วได้ด้วยคำสั่ง สถานที่เกิดเหตุ - a.

กำลังเตรียมตารางเปรียบเทียบของคุณ

ตอนนี้ ด้วยความรู้นี้ คุณสามารถสร้างตารางเปรียบเทียบสตริงในอุดมคติของคุณเองได้ ตารางนี้ควรเปรียบเทียบตัวอักษรรัสเซียอย่างถูกต้องรวมถึงตัวอักษรЁและในเวลาเดียวกันก็คำนึงถึงเครื่องหมายวรรคตอนตามตาราง ASCII.

ขั้นตอนการเตรียมตารางการเรียงลำดับของคุณเองประกอบด้วย XNUMX ขั้นตอน คือ การแก้ไขตารางน้ำหนัก และคอมไพล์ให้อยู่ในรูปแบบไบนารี่ด้วยคำสั่ง localdef.

เพื่อให้ตารางเปรียบเทียบสามารถปรับค่าแก้ไขได้น้อยที่สุดในรูปแบบ ISO.14652 มีส่วนสำหรับการปรับน้ำหนักของตารางที่มีอยู่ ส่วนเริ่มต้นด้วยคำสำคัญ จัดลำดับใหม่หลัง และระบุตำแหน่งหลังจากทำการเปลี่ยนแล้ว ส่วนที่ลงท้ายด้วยบรรทัด เรียงลำดับใหม่-สิ้นสุด. หากจำเป็นต้องแก้ไขหลายส่วนของตาราง จะมีการสร้างส่วนสำหรับแต่ละส่วนดังกล่าว

ฉันคัดลอกไฟล์เวอร์ชันใหม่แล้ว iso14651_t1_common и ru_ru จากพื้นที่เก็บข้อมูล glibc ไปยังโฮมไดเร็กตอรี่ของฉัน ~/.local/share/i18n/locales/ และแก้ไขส่วนเล็กน้อย LC_COLLATE в ru_ru. ไฟล์เวอร์ชันใหม่เข้ากันได้กับเวอร์ชันของฉันอย่างสมบูรณ์ glibc. หากคุณต้องการใช้ไฟล์เวอร์ชันเก่า คุณจะต้องเปลี่ยนชื่อสัญลักษณ์และตำแหน่งที่เริ่มการแทนที่ในตาราง

LC_COLLATE
% Copy the template from ISO/IEC 14651
copy "iso14651_t1"
reorder-after <U000D>
<U0020> <S0020>;<BASE>;<MIN>;<U0020> % SPACE
<U0021> <S0021>;<BASE>;<MIN>;<U0021> % EXCLAMATION MARK
<U0022> <S0022>;<BASE>;<MIN>;<U0022> % QUOTATION MARK
...
<U007D> <S007D>;<BASE>;<MIN>;<U007D> % RIGHT CURLY BRACKET
<U007E> <S007E>;<BASE>;<MIN>;<U007E> % TILDE
reorder-end
END LC_COLLATE

จริงๆ แล้วจำเป็นต้องเปลี่ยนช่องด้วย LC_IDENTIFICATION เพื่อให้ชี้ไปที่สถานที่นั้น ru_MYแต่ในตัวอย่างของฉัน สิ่งนี้ไม่จำเป็น เนื่องจากฉันได้แยกไฟล์เก็บถาวรออกจากการค้นหาสถานที่ สถานที่เก็บถาวร.

ที่ localdef ทำงานกับไฟล์ในโฟลเดอร์ของฉันผ่านตัวแปร I18NPAT คุณสามารถเพิ่มไดเร็กทอรีเพิ่มเติมเพื่อค้นหาไฟล์อินพุต และสามารถระบุไดเร็กทอรีเพื่อบันทึกไฟล์ไบนารีเป็นพาธที่มีเครื่องหมายทับได้:

$> I18NPATH=~/.local/share/i18n localedef -i ru_RU -f UTF-8 ~/.local/lib/locale/ru_MY.UTF-8

POSIX แนะนำว่าใน ภาษา คุณสามารถเขียนเส้นทางที่แน่นอนไปยังไดเร็กทอรีด้วยไฟล์โลแคลโดยเริ่มจากเครื่องหมายทับ แต่ glibc в ลินุกซ์ เส้นทางทั้งหมดนับจากไดเร็กทอรีฐาน ซึ่งสามารถแทนที่ได้ผ่านตัวแปร ล็อคพาธ. หลังการติดตั้ง LOCPATH=~/.local/lib/locale/ ไฟล์ทั้งหมดที่เกี่ยวข้องกับการแปลจะถูกค้นหาในโฟลเดอร์ของฉันเท่านั้น เก็บถาวรโลแคลด้วยชุดตัวแปร ล็อคพาธ ละเว้น

นี่คือการทดสอบขั้นเด็ดขาด:

$> LANG=ru_MY.UTF-8 LOCPATH=~/.local/lib/locale/ sort buhg.txt
Абаканов Михаил;маляр
Ёлкина Элла;крановщица
Иванов Андрей;слесарь
Иванова Алла;адвокат

ไชโย! เราทำได้!

ข้อผิดพลาดบาง

ฉันได้ตอบคำถามเกี่ยวกับการเรียงลำดับสตริงที่วางไว้ตั้งแต่ต้นแล้ว แต่ยังมีคำถามสองสามข้อเกี่ยวกับข้อผิดพลาด - มองเห็นและมองไม่เห็น

ลองกลับไปสู่ปัญหาเดิม

และโปรแกรม ประเภท และโปรแกรม ร่วม ใช้ฟังก์ชันการเปรียบเทียบสตริงเดียวกันจาก glibc. มันเกิดขึ้นได้อย่างไร ร่วม ให้ข้อผิดพลาดในการเรียงลำดับแถวที่เรียงลำดับตามคำสั่ง ประเภท ในสถานที่ th_US.UTF-8? คำตอบนั้นง่าย: ประเภท เปรียบเทียบสตริงทั้งหมดและ ร่วม เปรียบเทียบเฉพาะคีย์ ซึ่งโดยค่าเริ่มต้นคือจุดเริ่มต้นของสตริงจนถึงอักขระช่องว่างตัวแรก ในตัวอย่างของฉัน สิ่งนี้ส่งผลให้เกิดข้อความแสดงข้อผิดพลาดเนื่องจากการเรียงลำดับคำแรกในบรรทัดไม่ตรงกับการเรียงลำดับของบรรทัดทั้งหมด

สถานที่ "C" รับประกันว่าในสตริงที่เรียงลำดับ สตริงย่อยเริ่มต้นจนถึงช่องว่างแรกจะถูกจัดเรียงด้วย แต่จะปกปิดข้อผิดพลาดเท่านั้น สามารถเลือกข้อมูลได้ (ผู้ที่มีนามสกุลเดียวกันแต่ชื่อต่างกัน) ซึ่งจะทำให้ผลลัพธ์การรวมไฟล์ไม่ถูกต้องหากไม่มีข้อความแสดงข้อผิดพลาด หากเราต้องการ ร่วม รวมบรรทัดไฟล์ตามชื่อเต็ม ดังนั้นวิธีที่ถูกต้องคือระบุตัวคั่นฟิลด์อย่างชัดเจนและเรียงลำดับตามฟิลด์คีย์ ไม่ใช่ตามทั้งบรรทัด ในกรณีนี้ การรวมจะดำเนินการอย่างถูกต้องและจะไม่มีข้อผิดพลาดในภาษาใดๆ:

$> sort -t ; -k 1 buhg.txt > buhg.srt
$> sort -t ; -k 1 mail.txt > mail.srt
$> join -t ; buhg.srt mail.srt > result

ดำเนินการตัวอย่างสำเร็จในการเข้ารหัส CP1251 มีข้อผิดพลาดอื่น ความจริงก็คือว่าในการแจกแจงทั้งหมดที่ฉันรู้จัก ลินุกซ์ แพ็คเกจไม่มีโลแคลที่คอมไพล์แล้ว ru_RU.CP1251. หากไม่พบโลแคลที่คอมไพล์แล้ว ประเภท ใช้การเปรียบเทียบแบบไบต์ต่อไบต์อย่างเงียบๆ ซึ่งเป็นสิ่งที่เราสังเกตเห็น

อย่างไรก็ตาม มีข้อผิดพลาดเล็กๆ น้อยๆ อีกประการหนึ่งที่เกี่ยวข้องกับการไม่สามารถเข้าถึงโลแคลที่คอมไพล์ได้ ทีม LOCPATH=/tmp สถานที่ -a จะแสดงรายชื่อสถานที่ทั้งหมดใน สถานที่เก็บถาวรแต่ด้วยชุดตัวแปร ล็อคพาธ สำหรับทุกโปรแกรม (รวมทั้งโปรแกรมส่วนใหญ่ ในประเทศ) สถานที่เหล่านี้จะไม่สามารถใช้ได้

$> LOCPATH=/tmp locale -a | grep en_US
locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
locale: Cannot set LC_COLLATE to default locale: No such file or directory
en_US
en_US.iso88591
en_US.iso885915
en_US.utf8

$> LC_COLLATE=en_US.UTF-8 sort --debug
sort: using ‘en_US.UTF-8’ sorting rules

$> LOCPATH=/tmp LC_COLLATE=en_US.UTF-8 sort --debug
sort: using simple byte comparison

ข้อสรุป

หากคุณเป็นโปรแกรมเมอร์ที่คุ้นเคยกับการคิดว่าสตริงเป็นชุดของไบต์ คุณก็เป็นทางเลือกของคุณ LC_COLLATE=ค.

หากคุณเป็นนักภาษาศาสตร์หรือนักแปลพจนานุกรม คุณควรคอมไพล์ในภาษาของคุณดีกว่า

หากคุณเป็นผู้ใช้ธรรมดาคุณเพียงแค่ต้องทำความคุ้นเคยกับคำสั่งนั้น ls -a ไฟล์เอาท์พุตที่ขึ้นต้นด้วยจุดผสมกับไฟล์ที่ขึ้นต้นด้วยตัวอักษร และ ผู้บัญชาการเที่ยงคืนซึ่งใช้ฟังก์ชันภายในเพื่อจัดเรียงชื่อ โดยวางไฟล์ที่ขึ้นต้นด้วยจุดที่จุดเริ่มต้นของรายการ

การอ้างอิง

รายงานหมายเลข 10 อัลกอริธึมการจัดเรียง Unicode

น้ำหนักอักขระที่ unicode.org

ไอซียู — การใช้งานไลบรารีสำหรับการทำงานกับ Unicode จาก IBM

การทดสอบการเรียงลำดับโดยใช้ ไอซียู

น้ำหนักตัวละครเข้า ISO.14651

คำอธิบายรูปแบบไฟล์พร้อมสเกล ISO.14652

การอภิปรายการเปรียบเทียบสตริงใน glibc

ที่มา: will.com

เพิ่มความคิดเห็น