ทำไมการเรียงลำดับจึงบอกว่าɛ = e


25

ɛ("ละติน epsilon") เป็นจดหมายที่ใช้ในบางภาษาแอฟริกันมักจะเป็นตัวแทนของเสียงสระในภาษาอังกฤษ "เตียง" ใน Unicode มันถูกเข้ารหัสเป็น U + 025B ซึ่งแตกต่างจากทุกวันeมาก

อย่างไรก็ตามถ้าฉันsortต่อไปนี้:

eb
ed
ɛa
ɛc

ดูเหมือนว่าจะsortพิจารณาɛและeเทียบเท่า:

ɛa
eb
ɛc
ed

เกิดอะไรขึ้นที่นี่? และมีวิธีที่จะสร้างɛและeแยกแยะเพื่อsortวัตถุประสงค์?


21
กฎการเรียงลำดับเรียกว่า 'การเรียง' ถ้ามันช่วยคุณ googling
BlueRaja - Danny Pflughoeft

1
พยายามที่จะใส่จำนวนหนึ่งeaผสมกับɛaภายในไฟล์ข้อความและจัดเรียงมัน คุณจะเห็นว่ามันก็แปลก ๆก่อนea ɛaดังนั้นไม่ถือว่าไม่เท่ากัน
Bakuriu

อาจเป็นจุดที่ชัดเจน แต่ฉันไม่ได้เห็นมันแนะนำอย่างชัดเจนยัง: ถ้าคุณเรียงลำดับคำใน
Federico Poloni

@FedericoPoloni เป็นจุดที่ดีมาก! น่าเสียดายที่ฉันไม่สามารถค้นหาภาษาสำหรับภาษานี้ได้
Draconis

1
@ GermánBouzasนี่คือ "Latin epsilon" โดยเฉพาะรูปแบบที่ออกแบบมาเพื่อให้สอดคล้องกับตัวอักษรละติน พวกเขาดูเหมือนกันมาก แต่ละติน epsilon คือ U + 025B ในขณะที่ epsilon กรีกคือ U + 03B5
Draconis

คำตอบ:


67

ไม่ไม่ถือว่าพวกเขาเทียบเท่า แต่พวกเขามีน้ำหนักหลักเท่ากัน ดังนั้นในการประมาณครั้งแรกพวกมันก็เรียงแบบเดียวกัน

หากคุณดู / usr / share / i18n / locales / iso14651_t1_common (ซึ่งใช้เป็นพื้นฐานสำหรับโลแคลส่วนใหญ่) บนระบบ GNU (ที่นี่ด้วย glibc 2.27) คุณจะเห็น:

<U0065> <e>;<BAS>;<MIN>;IGNORE # 259 e
<U025B> <e>;<PCL>;<MIN>;IGNORE # 287 ɛ
<U0045> <e>;<BAS>;<CAP>;IGNORE # 577 E

e, ɛและEมีน้ำหนักหลักเดียวกันeและEน้ำหนักรองเดียวกันเพียงสามน้ำหนักแตกต่างได้

เมื่อเปรียบเทียบสตริงsort( strcoll()ฟังก์ชัน libc มาตรฐานจะใช้ในการเปรียบเทียบสตริง) เริ่มต้นโดยการเปรียบเทียบน้ำหนักหลักของตัวละครทั้งหมดและไปที่น้ำหนักที่สองเท่านั้นหากสตริงเท่ากับน้ำหนักหลัก (และอื่น ๆ ด้วยน้ำหนักอื่น ๆ ) .

นั่นเป็นกรณีที่ดูเหมือนว่าจะถูกละเว้นในการเรียงลำดับในการประมาณครั้งแรก Abทุกประเภทระหว่างaaและacแต่Abสามารถเรียงลำดับก่อนหรือหลังabขึ้นอยู่กับกฎภาษา (บางภาษามี<MIN>มาก่อน<CAP>เช่นเดียวกับในอังกฤษบางส่วน<CAP>ก่อนที่จะ<MIN>เหมือนในเอสโตเนีย)

หากeมีการเรียงลำดับเช่นเดียวกับɛ, printf '%s\n' e ɛ | sort -uจะกลับมาเพียงหนึ่งบรรทัด แต่เป็น<BAS>ประเภทก่อน<PCL>, eประเภทคนเดียวก่อน เรียงลำดับตาม(ที่น้ำหนักรอง) แม้ว่าจะเรียงลำดับตามหลัง(ซึ่งเราจำเป็นต้องขึ้นสู่น้ำหนักที่สาม)ɛeɛeEEEEEEeee

ตอนนี้ถ้าในระบบของฉันด้วย glibc 2.27 ฉันเรียกใช้:

sed -n 's/\(.*;[^[:blank:]]*\).*/\1/p' /usr/share/i18n/locales/iso14651_t1_common |
  sort -k2 | uniq -Df1

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

<U01DD> <e>;<PCL>;<MIN>;IGNORE
<U0259> <e>;<PCL>;<MIN>;IGNORE
<U025B> <e>;<PCL>;<MIN>;IGNORE

และนั่นเอง:

$ printf '%s\n' $'\u01DD' $'\u0259' $'\u025B' | sort -u
ǝ
$ expr ɛ = ǝ
1

ที่สามารถมองเห็นเป็นข้อบกพร่องของสถานที่ libc GNU ในระบบอื่น ๆ ส่วนใหญ่โลแคลต้องแน่ใจว่าอักขระที่แตกต่างกันทั้งหมดมีลำดับการเรียงลำดับที่แตกต่างกันในตอนท้าย เกี่ยวกับสถานที่ของ GNU ได้รับก็แย่ตามที่มีมากมายของตัวละครที่ไม่ได้มีคำสั่งการเรียงลำดับและจบลงด้วยการเรียงลำดับเดียวกันที่ก่อให้เกิดปัญหาทุกประเภท (เช่นหมดcomm, join, lsหรือ globs มีคำสั่งซื้อที่ไม่ได้กำหนด ... ) จึงเสนอแนะของการใช้LC_ALL=Cเพื่อหลีกเลี่ยงปัญหาเหล่านั้น

ตามที่บันทึกไว้โดย @ninjalj ในความคิดเห็น glibc 2.28 ที่ปล่อยออกมาในเดือนสิงหาคม 2561 มาพร้อมกับการปรับปรุงบางอย่างที่ด้านหน้าแม้ว่า AFAICS ยังมีตัวละครหรือองค์ประกอบการเรียงที่กำหนดด้วยลำดับการเรียงเหมือนกัน บน Ubuntu 18.10 พร้อม glibc 2.28 และในภาษา en_GB.UTF-8

$ expr $'L\ub7' = $'L\u387'
1

(เพราะเหตุใด U + 00B7 จึงถูกพิจารณาว่าเทียบเท่ากับ U + 0387 เมื่อรวมกับL/ ?! l)

และ:

$ perl -lC -e 'for($i=0; $i<0x110000; $i++) {$i = 0xe000 if $i == 0xd800; print chr($i)}' | sort > all-chars-sorted
$ uniq -d all-chars-sorted | wc -l
4
$ uniq -D all-chars-sorted | wc -l
1061355

(ยังมีมากกว่า 1 ล้านตัวอักษร (95% ของช่วง Unicode ลดลงจาก 98% ใน 2.27) การเรียงลำดับเหมือนกับตัวอักษรอื่น ๆ เนื่องจากไม่ได้กำหนดลำดับการเรียงลำดับ)

ดูสิ่งนี้ด้วย:


3
นี่คือสิ่งที่ฉันกำลังมองหา! เพื่อความสมบูรณ์สิ่งที่<PCL>ยืนหยัดเพื่อ? คนอื่น ๆ ดูเหมือนจะเป็นทุน Miniscule และพื้นฐาน?
Draconis

3
@ Draconis, collating-symbol <PCL> # 16 อนุภาค / แปลกประหลาด
Stéphane Chazelas

แน่นอนถ้าเราใส่มัดeaและɛaผสมเข้าด้วยกันในไฟล์เราจะเห็นว่ามันsortเรียงลำดับทั้งหมดeaก่อนหน้าɛas
Bakuriu

2
จาก glibc 2.28, codepoint ควรใช้เป็นทางเลือกสำหรับน้ำหนักระดับที่ 4 ดูsourceware.org/git/.. sourceware.org/bugzilla/show_bug.cgi?id=14095
ninjalj

1
@cat ขอโทษฉันหมายถึงstrcoll()ดูแก้ไข
Stéphane Chazelas

15

คนจัดเรียง:

   ***  WARNING  ***  The locale specified by the environment affects sort
   order.  Set LC_ALL=C to get the traditional sort order that uses native
   byte values.

ดังนั้นลอง: LC_ALL=C sort file.txt


1
ได้ผลจริง! แต่ทำไมโลแคลที่เป็นค่าเริ่มต้นจึงถือว่า codepoints ที่แยกจากกันเหล่านี้เหมือนกัน ฉันสงสัยว่าทำไมสิ่งนี้เกิดขึ้น
Draconis

@Draconis "ภาษาเริ่มต้น" คืออะไร
Kamil Maciorowski

@KamilMaciorowski ค่าว่างของตัวแปรสภาพแวดล้อม ฉันไม่แน่ใจว่าสถานที่ที่สอดคล้องกับอะไร
Draconis

3
@Draconis ถ้าLC_ALLว่างเปล่าsortอาจใช้LC_*ตัวแปรอื่น ๆLANGหรือไฟล์การกำหนดค่าบางอย่าง
NieDzejkob

1
LC_COLLATEเป็นสตริงเฉพาะการเรียงลำดับเป็นหนึ่งLANGพิเศษทั่วไป
ShadowRanger

8

อักขระɛไม่เท่ากับ e แต่สถานที่บางแห่งสามารถรวบรวมสัญญาณเหล่านี้ได้ใกล้เคียงกันเมื่อมีการเปรียบเทียบ เหตุผลนี้เป็นภาษาเฉพาะ แต่ยังมีภูมิหลังทางประวัติศาสตร์หรือทางการเมืองบางอย่าง ตัวอย่างเช่นคนส่วนใหญ่อาจคาดหวังว่าสกุลเงิน€ uroมาใกล้กับพจนานุกรมในยุโรป

อย่างไรก็ตามจะเห็นสิ่งที่เปรียบเทียบคุณกำลังใช้การทำงานlocaleที่locale -aจะทำให้คุณมีรายชื่อของสถานที่ที่มีอยู่ในระบบและการเปลี่ยนแปลงการเปรียบเทียบพูดไปเพียงสำหรับหนึ่งวิ่งเรียงลำดับC LC_COLLATE=C sort fileสุดท้ายเพื่อดูว่าสถานที่ต่างกันสามารถเรียงลำดับไฟล์ของคุณได้อย่างไร

for loc in $(locale -a)
    do echo ____"${loc}"____
    LC_COLLATE="$loc" sort file
done

วางผลลัพธ์ลงในเครื่องมือ greping เพื่อเลือกโลแคลที่เหมาะกับความต้องการของคุณ


นี่เป็นคำอธิบายที่ยอดเยี่ยม แต่สัญลักษณ์ดูเหมือนว่าจะเหมือนกันไม่ใช่แค่ใกล้กัน
Draconis

1
ไม่พวกเขาไม่ถือว่าเหมือนกัน เพิ่มeaบรรทัดธรรมดาลงในไฟล์จากนั้นsort -uคุณจะได้รับทั้งสองeaและɛaในผลลัพธ์ กลยุทธ์ที่ดีที่สุดกับการเปรียบเทียบคือการหลีกเลี่ยง ( export LC_COLLATE=C) มิฉะนั้นสิ่งที่น่าเกลียดมากจะเกิดขึ้น (เช่น. /tmp/[a-z]ในbashจะตรง/tmp/aและ/tmp/Aแต่ไม่/tmp/Z)
mosvy

@mosvy Huh น่าสนใจ ... ดังนั้นพวกเขาจึงถือว่าเหมือนกันสำหรับวัตถุประสงค์ในการสั่งซื้อ แต่ไม่ใช่เพื่อจุดประสงค์ที่ไม่ซ้ำใคร
Draconis

พวกเขาไม่ถือว่าเหมือนกัน ดูที่นี่คำอธิบายเกี่ยวกับมัน
mosvy

1
@ninjalj ที่อาจได้รับการแก้ไขใน glibc fnmatch()และ regexp ช่วง แต่ไม่ได้อยู่ในบางอย่างเช่นที่ใช้ช่วงของมันด้วยตัวเองโดยใช้bash strcoll()ksh93 ไม่เคยมีปัญหาเนื่องจากการใช้ช่วงนั้นใช้strcoll()และตรวจสอบกรณีของช่วงสิ้นสุดและจับคู่กับอักขระตัวพิมพ์เล็กเท่านั้นหากทั้งสองด้านเป็นตัวพิมพ์เล็ก ช่วง zsh ไม่มีปัญหาเนื่องจากทำตามจุดโค้ดไม่ใช่ strcoll ()
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.