LC_COLLATE có nên ảnh hưởng đến phạm vi ký tự không?


27

Thứ tự đối chiếu thông qua LC_COLLATEđịnh nghĩa không chỉ thứ tự sắp xếp của từng ký tự mà còn cả ý nghĩa của phạm vi ký tự. Hay không? Hãy xem xét đoạn trích sau:

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

Theo trực giác, Bkhông phải trong [a-z], vì vậy điều này không nên xuất ra bất cứ điều gì. Đó là những gì xảy ra trên Ubuntu 8.04 hoặc 10.04. Nhưng trên một số máy chạy lenny Debian hoặc bóp, Bđược tìm thấy, bởi vì phạm vi a-zbao gồm tất cả mọi thứ đó là giữa aztheo thứ tự đối chiếu, bao gồm cả chữ in hoa Bqua Z.

Tất cả các hệ thống được thử nghiệm đều có en_USmiền địa phương được tạo ra. Tôi cũng đã thử thay đổi ngôn ngữ khác nhau: trên các máy Bđược khớp ở trên, điều tương tự cũng xảy ra ở mọi ngôn ngữ có sẵn (chủ yếu dựa trên tiếng Latin : {en_{AU,CA,GB,IE,US},fr_FR,it_IT,es_ES,de_DE}{iso8859-1,iso8859-15,utf-8}, cũng là tiếng Trung Quốc) ngoại trừ tiếng Nhật (trong bất kỳ mã hóa có sẵn nào) và C/ POSIX.

Phạm vi ký tự có ý nghĩa gì trong các biểu thức thông thường , khi bạn vượt ra ngoài ASCII? Tại sao có một sự khác biệt giữa một số cài đặt Debian một mặt và mặt khác các cài đặt Debian và Ubuntu? Làm thế nào để các hệ thống khác hành xử? Ai đúng và ai nên báo cáo lỗi?

(Lưu ý rằng tôi đặc biệt yêu cầu về hành vi của nhân vật dao động như [a-z]trong en_USmiền địa phương, chủ yếu là trên các hệ thống libc dựa trên GNU. Tôi không yêu cầu như thế nào để phù hợp với chữ thường hoặc chữ ASCII chữ thường.)


Trên hai máy Debian, một máy Bở trong [a-z]và một máy không có, đầu ra LC_COLLATE=en_US locale -k LC_COLLATE

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

và đầu ra của LC_COLLATE=en_US.utf8 locale -k LC_COLLATE

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

1
Không sao chép trên phiên bản Debian Lenny mà tôi đã có. Không kiểm tra nếu en_USđược tạo ra, mặc dù.
alex

1
@alex Nếu miền địa phương không được tạo, Cmiền địa phương được sử dụng làm dự phòng và thứ tự đối chiếu của nó là các giá trị byte thẳng, do đó Bsẽ không được khớp. Kiểm tra tại một địa điểm xuất hiện trong đầu ra của locale -a.
Gilles 'SO- đừng trở nên xấu xa'

1
Lưu ý rằng en_US KHÔNG giống như en_US.utf8 và thường có nghĩa là en_US.iso-8859-1, tùy thuộc vào chính xác những gì bạn đã cài đặt. Nếu en_US (không có hậu tố) không xuất hiện trong đầu ra của miền địa phương - thì bạn không thực sự có miền địa phương này. LC_COLLATE = en_US locale -k LC_COLLATE hiển thị gì?
Neil Mayhew

1
Điều này đã xuất hiện trong một câu hỏi thực tế thay vì lý thuyết ở đây: Tại sao các chữ in hoa được bao gồm trong một loạt các chữ cái viết thường trong một biểu thức chính thức?
Caleb

1
@isaac Thật không may, 7 năm sau, tôi dường như không có quyền truy cập vào bất kỳ hệ thống có vấn đề nào. Tất cả đều được nâng cấp hoặc ngừng hoạt động.
Gilles 'SO- ngừng trở nên xấu xa'

Câu trả lời:


3

Nếu bạn đang sử dụng bất cứ thứ gì khác ngoài Cmiền địa phương, bạn không nên sử dụng các phạm vi như [a-z]vì chúng phụ thuộc vào miền địa phương và không luôn đưa ra kết quả mà bạn mong đợi. Cũng như vấn đề trường hợp bạn đã gặp phải, một số địa phương đối xử với các ký tự có dấu phụ (ví dụ á ) giống như ký tự cơ sở (ví dụ a ).

Thay vào đó, sử dụng một lớp nhân vật được đặt tên:

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

Điều này sẽ luôn đưa ra kết quả chính xác cho miền địa phương. Tuy nhiên, bạn cần chọn ngôn ngữ để phản ánh ý nghĩa của cả văn bản đầu vào của bạn và bài kiểm tra bạn đang cố gắng áp dụng.

Ví dụ: nếu bạn cần tìm một giá trị byte cụ thể, hãy sử dụng Cngôn ngữ luôn có sẵn:

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

Nếu điều này không hoạt động như mong đợi, nó thực sự là một lỗi.


Tôi biết rằng, đó không phải là những gì tôi yêu cầu. Tôi đặc biệt hỏi về ý nghĩa của một phạm vi rõ ràng và tại sao các bản phân phối khác nhau (ngay cả với GNU libc và GNU grep) có các hành vi khác nhau. (Bị từ chối vì mặc dù những gì bạn nói là chính xác, nhưng điều đó không liên quan.)
Gilles 'SO- ngừng trở nên xấu xa'

1
Quan điểm của tôi là ý nghĩa của một phạm vi rõ ràng phụ thuộc vào miền địa phương và các hệ thống khác nhau không bắt buộc phải xác định vị trí của chúng theo cùng một cách, vì vậy đây không phải là một lỗi. Về mặt kỹ thuật, bạn đang lạm dụng hệ thống, vì vậy bạn không nên ngạc nhiên khi nhận được hành vi "không xác định". Ngoài ra, một số người đã nhận xét rằng họ không thể tái tạo hành vi trên các hệ thống Debian của họ, vì vậy dường như có điều gì đó bất thường về (các) hệ thống của bạn.
Neil Mayhew

1
Tôi biết rằng hành vi của các phạm vi phụ thuộc vào địa phương. Tôi đang hỏi làm thế nào và ngạc nhiên rằng các hệ thống khác nhau sử dụng Glibc (và, hóa ra, ngay cả các bản cài đặt khác nhau của cùng một bản phát hành Debian) có các hành vi khác nhau. Tôi đã thêm đầu ra locale -kcho câu hỏi của mình; nó giống hệt nhau trên hai máy Debian, một Bở trong phạm vi và một ở không. BTW Tôi không root trên cả hai máy (vì vậy đó không phải là điều gì đó đặc biệt mà tôi làm với tư cách là quản trị viên).
Gilles 'SO- đừng trở nên xấu xa'

echo "Baü" | LC_COLLATE=C grep -o '[[:lower:]]'trả về aütrong khi echo "Baü" | LC_COLLATE=C grep -o '[a-z]'chỉ trả về a. Trong mắt tôi, "thấp hơn" không thực sự là điều OP muốn
Daniel Alder

Tuy nhiên, điểm ban đầu của tôi vẫn đứng: không sử dụng phạm vi trừ khi bạn ở Cđịa phương. Tôi tin rằng điều này có liên quan đến OP, người đang tìm cách báo cáo lỗi. Nếu bạn không ở Cđịa phương, kết quả của việc sử dụng phạm vi rất khó đoán và do đó không bao giờ được coi là một lỗi. Mặt khác, nếu bạn cần tìm một giá trị byte cụ thể, chỉ cần sử dụng Cngôn ngữ. Điểm phụ của tôi là nếu bạn thực sự muốn tìm kiếm các chữ cái viết thường trong một miền địa phương, hãy sử dụng một lớp ký tự. Mặc dù OP có thể đã không tìm kiếm điều này, những người khác có thể nếu họ tìm thấy câu hỏi này.
Neil Mayhew

1

Phạm vi trong biểu thức chính quy nên quan sát cài đặt đối chiếu. Dưới đây là tiêu chuẩn có liên quan: http://pub.opengroup.org/onlinepub/007908799/xbd/re.html (tìm "biểu thức phạm vi"). Vì vậy, echo B | LC_COLLATE=en_US grep '[a-z]'đầu ra nên Bđưa ra một định nghĩa hợp lý của miền địa phương tương ứng. Tôi không thể giải thích lý do tại sao điều này đôi khi không hiệu quả với bạn, nhưng tôi sẽ rất ngạc nhiên nếu tôi gặp phải điều này trên một hệ thống không cổ xưa được cài đặt và cấu hình đúng.


1
echo B | LC_COLLATE=en_US.utf8 grep '[a-z]' Không in bất cứ thứ gì trên Ubuntu 12.04 với grep 2.10. Không in bất cứ thứ gì trên Centos 6.5 với grep 2.6.3. Không hoạt động trên Debian 6.0.8 với grep 2.6.3.
Ian D. Allen
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.