2009-09-03 34 views
14

Nếu tôi thực hiện các tuyên bố sau:Tại sao string.Compare dường như xử lý các ký tự có dấu không nhất quán?

string.Compare("mun", "mün", true, CultureInfo.InvariantCulture) 

Kết quả là '-1', chỉ ra rằng 'mun' có một giá trị số thấp hơn so với 'Mun'.

Tuy nhiên, nếu tôi thực hiện tuyên bố này:

string.Compare("Muntelier, Schweiz", "München, Deutschland", true, CultureInfo.InvariantCulture) 

tôi nhận được '1', chỉ ra rằng 'muntelier, Schewiz' nên đi trước.

Đây có phải là lỗi trong so sánh không? Hoặc, nhiều khả năng, là có một quy tắc tôi nên được tính đến khi sắp xếp chuỗi có chứa dấu


Lý do này là một vấn đề là, tôi đang sắp xếp một danh sách và sau đó thực hiện một bộ lọc nhị phân của nhãn hiệu đó có nghĩa là để có được mọi chuỗi bắt đầu bằng 'xxx'.

Trước đây tôi đã sử dụng phương pháp Linq 'Where', nhưng bây giờ tôi phải sử dụng chức năng tùy chỉnh này được viết bởi một người khác, bởi vì anh ấy nói nó hoạt động tốt hơn.

Nhưng chức năng tùy chỉnh dường như không tính đến bất kỳ quy tắc 'unicode' nào .NET có. Vì vậy, nếu tôi nói với nó để lọc bằng 'mün', nó không tìm thấy bất kỳ mục nào, mặc dù có các mục trong danh sách bắt đầu bằng 'mun'.

Điều này có vẻ là do thứ tự không nhất quán của các ký tự có dấu, tùy thuộc vào ký tự nào sau ký tự có dấu trọng âm.


OK, tôi nghĩ rằng tôi đã khắc phục được sự cố.

Trước khi lọc, tôi làm một loại dựa trên n chữ cái đầu tiên của mỗi chuỗi, nơi n là chiều dài của chuỗi tìm kiếm.

+0

Đó là những khoảnh khắc như thế này mà tôi muốn .NET Framework là mã nguồn mở, vì vậy tôi chỉ có thể xem qua trong chế độ gỡ lỗi và tìm ra chính xác những gì nó đang làm. – Jonathan

+4

@jonathanconway: Bước qua mã nguồn của thư viện lớp cơ sở là có thể, xem http://blogs.msdn.com/sburke/archive/2008/01/16/configuring-visual-studio-to-debug-net- framework-source-code.aspx –

+0

@divo Cảm ơn bạn đã tham khảo. Không bao giờ nhận ra điều này là có thể! – Jonathan

Trả lời

22

Có một thuật toán tie phá tại nơi làm việc, xem http://unicode.org/reports/tr10/

Để giải quyết sự phức tạp của phân loại ngôn ngữ nhạy cảm, một thuật toán so sánh đa cấp là sử dụng. Khi so sánh hai từ, với ví dụ , đối tượng quan trọng nhất là ký tự cơ sở: chẳng hạn như sự khác biệt giữa A và B. Sự khác biệt về phần trăm thường là bị bỏ qua, nếu có khác biệt trong các chữ cái gốc. Trường hợp sự khác biệt (chữ hoa so với chữ thường), là thường bị bỏ qua, nếu có bất kỳ sự khác biệt nào trong số cơ sở hoặc dấu trọng âm . Dấu câu là biến. Trong một số trường hợp , một ký tự dấu chấm câu là được xử lý như một ký tự cơ sở. Trong các tình huống khác, cần bỏ qua nếu có bất kỳ cơ sở, dấu trọng âm hoặc trường hợp nào khác nhau sự khác biệt. Cũng có thể có cấp độ cuối cùng, mức ràng buộc , theo đó nếu không có khác biệt nào khác ở tất cả trong chuỗi, thì mã (mã hóa chuẩn) được sử dụng.

Vì vậy, "Munt ..." và "Münc ..." khác biệt theo thứ tự bảng chữ cái và sắp xếp dựa trên "t" và "c".

Trong khi đó, "mun" và "Mun" là thứ tự abc như nhau ("u" equivelent để "ü" trong ngôn ngữ mất) để mã ký tự được so sánh

6

Có vẻ như ký tự có dấu trọng âm chỉ được sử dụng trong một tình huống "ngắt kết nối" - nói cách khác, nếu các chuỗi khác nhau.

Dưới đây là một số mẫu mã để chứng minh: (. Tôi đã thử thêm một không gian sau khi "n" là tốt, để xem nếu nó được thực hiện trên ranh giới từ - nó không phải là)

using System; 
using System.Globalization; 

class Test 
{ 
    static void Main() 
    { 
     Compare("mun", "mün"); 
     Compare("muna", "münb"); 
     Compare("munb", "müna"); 
    } 

    static void Compare(string x, string y) 
    { 
     int result = string.Compare(x, y, true, 
            CultureInfo.InvariantCulture)); 

     Console.WriteLine("{0}; {1}; {2}", x, y, result); 
    } 
} 

Kết quả:

mun; mün; -1 
muna; münb; -1 
munb; müna; 1 

tôi nghi ngờ điều này là đúng bởi các quy tắc Unicode phức tạp khác nhau - nhưng tôi không biết đủ về họ.

Để biết liệu bạn có cần tính đến điều này ... Tôi không mong đợi như vậy. Bạn đang làm gì được ném bởi điều này?

4

Vì tôi hiểu điều này vẫn còn phần nào phù hợp. Khi so sánh sử dụng CultureInfo.InvariantCulture, ký tự umlaut ü được coi là ký tự không có dấu u.

Vì các chuỗi trong ví dụ đầu tiên của bạn rõ ràng không bằng kết quả sẽ không bằng 0 nhưng -1 (có vẻ là giá trị mặc định). Trong ví dụ thứ hai Muntelier sẽ hoạt động lần cuối vì t theo sau c trong bảng chữ cái.

tôi không thể tìm thấy bất kỳ tài liệu rõ ràng trong MSDN giải thích những quy tắc, nhưng tôi thấy rằng

string.Compare("mun", "mün", CultureInfo.InvariantCulture, 
    CompareOptions.StringSort); 

string.Compare("Muntelier, Schweiz", "München, Deutschland", 
    CultureInfo.InvariantCulture, CompareOptions.StringSort); 

cho kết quả mong muốn.

Dù sao thì, tôi nghĩ bạn nên dựa vào việc sắp xếp dựa trên một nền văn hóa cụ thể như văn hóa của người dùng hiện tại (nếu có thể).

+0

'CompareOptions.Ordinal' cũng có thể là một tùy chọn. Với tùy chọn này, các chuỗi sẽ được so sánh dựa trên các giá trị Unicode. Xem http://msdn.microsoft.com/en-us/library/system.globalization.compareoptions.aspx. –

Các vấn đề liên quan