LC_COLLATE (ควร) มีผลกับช่วงอักขระหรือไม่


27

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

unset LANGUAGE LC_ALL
echo B | LC_COLLATE=en_US grep '[a-z]'

สังหรณ์ใจBไม่ได้อยู่ใน[a-z]ดังนั้นสิ่งนี้ไม่ควรส่งออกอะไร นั่นคือสิ่งที่เกิดขึ้นบน Ubuntu 8.04 หรือ 10.04 แต่ในบางเครื่องทำงาน Debian Lenny หรือบีบBพบเพราะช่วงa-zรวมถึงทุกอย่างที่ระหว่างaและzเพื่อเปรียบเทียบรวมทั้งตัวอักษรทุนผ่านBZ

ระบบทั้งหมดที่ทำการทดสอบจะมีen_USสถานที่เกิดขึ้น ฉันยังพยายามที่แตกต่างกันสถานที่เกิดเหตุ: ในเครื่องที่Bจะถูกจับคู่ข้างต้นเดียวกันที่เกิดขึ้นในสถานบริการทุก (ส่วนใหญ่เป็นภาษาลาตินตาม: {en_{AU,CA,GB,IE,US},fr_FR,it_IT,es_ES,de_DE}{iso8859-1,iso8859-15,utf-8}ยังสถานที่ภาษาจีน) ยกเว้นญี่ปุ่น (ในการเข้ารหัสใด ๆ ) และ/CPOSIX

ช่วงของอักขระหมายความว่าอย่างไรในนิพจน์ทั่วไปเมื่อคุณไปเกิน ASCII เหตุใดจึงมีความแตกต่างระหว่างการติดตั้ง Debian บางอย่างในมือข้างหนึ่งและการติดตั้ง Debian อื่น ๆ และ Ubuntu ในอีกด้านหนึ่ง? ระบบอื่นทำงานอย่างไร? ใครถูกและใครควรจะรายงานบั๊ก?

(โปรดทราบว่าฉันถามเกี่ยวกับพฤติกรรมของช่วงอักขระเช่น[a-z]ในen_USตำแหน่งที่ตั้งโดยเฉพาะอย่างยิ่งในระบบที่ใช้ libc เป็นหลัก GNU ฉันไม่ได้ถามว่าจะจับคู่ตัวพิมพ์เล็กหรือตัวอักษรตัวพิมพ์เล็ก ASCII ได้อย่างไร)


สองเครื่อง Debian หนึ่งที่Bอยู่ใน[a-z]และเป็นหนึ่งในสถานที่ที่มันไม่ได้เป็นผลผลิตของการLC_COLLATE=en_US locale -k LC_COLLATEมี

collate-nrules=4
collate-rulesets=""
collate-symb-hash-sizemb=1
collate-codeset="ISO-8859-1"

และผลลัพธ์ของLC_COLLATE=en_US.utf8 locale -k LC_COLLATEคือ

collate-nrules=4
collate-rulesets=""
collate-symb-hash-sizemb=2039
collate-codeset="UTF-8"

1
ไม่ทำซ้ำบนอินสแตนซ์ของ Debian Lenny ที่ฉันเคยใช้มาแล้ว ไม่ได้ตรวจสอบว่าen_USมีการสร้างหรือไม่
alex

1
@alex หากไม่ได้สร้างCสถานที่เกิดเหตุจะใช้สถานที่เป็นทางเลือกและลำดับการเรียงเป็นค่าไบต์ตรงดังนั้นBจะไม่ถูกจับคู่ locale -aการทดสอบในสถานที่เกิดเหตุที่ปรากฏในการส่งออกของ
Gilles 'หยุดชั่วร้าย'

1
โปรดทราบว่า en_US ไม่เหมือนกับ en_US.utf8 และโดยทั่วไปจะหมายถึง en_US.iso-8859-1 ขึ้นอยู่กับสิ่งที่คุณติดตั้ง หาก en_US (ไม่มีคำต่อท้าย) ไม่ปรากฏในผลลัพธ์ของสถานที่ - คุณไม่ได้มีสถานที่นี้ LC_COLLATE = en_US locale -k LC_COLLATE แสดงอะไร
Neil Mayhew

1
สิ่งนี้ได้ปรากฏในการปฏิบัติมากกว่าคำถามเชิงทฤษฎีที่นี่: ทำไมตัวอักษรพิมพ์ใหญ่จึงรวมอยู่ในช่วงของตัวอักษรพิมพ์เล็กใน awk regex?
คาเลบ

1
@isaac น่าเสียดายที่ 7 ปีต่อมาฉันดูเหมือนจะไม่สามารถเข้าถึงระบบที่มีปัญหาได้ พวกเขาทั้งหมดได้รับการอัพเกรดหรือเลิกใช้งาน
Gilles 'หยุดความชั่วร้าย'

คำตอบ:


3

หากคุณกำลังใช้สิ่งอื่นนอกเหนือจากCภาษาคุณไม่ควรใช้ช่วงเช่น[a-z]นี้เนื่องจากขึ้นอยู่กับสถานที่และไม่ให้ผลลัพธ์ที่คุณคาดหวังเสมอ เช่นเดียวกับปัญหากรณีที่คุณพบแล้วสถานที่บางแห่งปฏิบัติต่อตัวละครที่มีกำกับ (เช่นá ) เหมือนกับตัวละครฐาน (เช่น )

ให้ใช้คลาสอักขระที่มีชื่อแทน:

echo B | grep '[[:lower:]]'

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

ตัวอย่างเช่นหากคุณต้องการค้นหาค่าไบต์เฉพาะให้ใช้Cโลแคลซึ่งมีอยู่เสมอ:

echo B | LANG=C grep '[a-z]'

หากสิ่งนี้ไม่ทำงานตามที่คาดไว้มันเป็นข้อผิดพลาดจริงๆ


ฉันรู้ว่ามันไม่ใช่สิ่งที่ฉันถาม ฉันถามเฉพาะเกี่ยวกับความหมายของช่วงที่ชัดเจนและเหตุใดการแจกแจงที่แตกต่างกัน (แม้กับ GNU libc และ GNU grep) มีพฤติกรรมที่แตกต่างกัน (ลงคะแนนเพราะแม้ว่าสิ่งที่คุณพูดนั้นถูกต้อง แต่ก็ไม่เกี่ยวข้อง)
Gilles 'ดังนั้นหยุดความชั่วร้าย'

1
ประเด็นของฉันคือความหมายของช่วงชัดเจนขึ้นอยู่กับสถานที่และระบบที่แตกต่างไม่จำเป็นต้องกำหนดสถานที่ของพวกเขาในลักษณะเดียวกันดังนั้นนี่ไม่ใช่ข้อผิดพลาด ในทางเทคนิคคุณกำลังใช้ระบบในทางที่ผิดดังนั้นคุณไม่ควรแปลกใจที่ได้รับพฤติกรรม "ไม่ได้กำหนด" นอกจากนี้หลายคนแสดงความคิดเห็นว่าพวกเขาไม่สามารถทำซ้ำพฤติกรรมบนระบบ Debian ของพวกเขาดังนั้นดูเหมือนว่าจะมีบางสิ่งผิดปกติเกี่ยวกับระบบของคุณ
Neil Mayhew

1
ฉันรู้ว่าพฤติกรรมของช่วงขึ้นอยู่กับสถานที่ ฉันถามว่าและแปลกใจที่ระบบต่าง ๆ ที่ใช้ Glibc (และมันกลับกลายเป็นว่าการติดตั้งเดเบียนรุ่นเดียวกันต่างกัน) มีพฤติกรรมที่แตกต่างกัน ฉันได้เพิ่มผลลัพธ์ของlocale -kคำถามของฉัน มันเหมือนกันกับเครื่อง Debian สองเครื่องเครื่องหนึ่งซึ่งBอยู่ในระยะและอีกเครื่องที่ไม่ใช่ BTW ฉันไม่ได้รูทบนเครื่องทั้งสอง (ดังนั้นจึงไม่ใช่เรื่องแปลกที่ฉันทำในฐานะผู้ดูแลระบบ)
Gilles 'หยุดความชั่วร้าย'

echo "Baü" | LC_COLLATE=C grep -o '[[:lower:]]'ผลตอบแทนaและüในขณะที่ผลตอบแทนเท่านั้นecho "Baü" | LC_COLLATE=C grep -o '[a-z]' aในสายตาของฉัน "ต่ำกว่า" ไม่ใช่สิ่งที่ OP ต้องการจริงๆ
Daniel Alder

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

1

ช่วงในการแสดงออกปกติควรสังเกตการตั้งค่าการเปรียบเทียบ นี่คือมาตรฐานที่เกี่ยวข้อง: http://pubs.opengroup.org/onlinepubs/007908799/xbd/re.html (มองหา "การแสดงออกของช่วง") ดังนั้นecho B | LC_COLLATE=en_US grep '[a-z]'เอาต์พุตควรBกำหนดนิยามที่สมเหตุสมผลของโลแคลที่เกี่ยวข้อง ฉันไม่สามารถอธิบายได้ว่าทำไมบางครั้งถึงไม่เหมาะกับคุณ แต่ฉันจะแปลกใจมากถ้าฉันพบสิ่งนี้ในระบบที่ไม่ใช่โบราณที่ติดตั้งและกำหนดค่าอย่างเหมาะสม


1
echo B | LC_COLLATE=en_US.utf8 grep '[a-z]' ไม่พิมพ์อะไรบน Ubuntu 12.04 ด้วย grep 2.10 ไม่พิมพ์อะไรบน Centos 6.5 ด้วย grep 2.6.3 ทำงานกับ Debian 6.0.8 ด้วย grep 2.6.3
Ian D. Allen
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.