2008-12-11 62 views
112

Tôi cần so sánh 2 chuỗi trong C# và xử lý các chữ cái có dấu giống như các chữ cái không có dấu. Ví dụ:Bỏ qua các chữ cái có dấu trong so sánh chuỗi

string s1 = "hello"; 
string s2 = "héllo"; 

s1.Equals(s2, StringComparison.InvariantCultureIgnoreCase); 
s1.Equals(s2, StringComparison.OrdinalIgnoreCase); 

2 chuỗi này cần phải giống nhau (theo như đơn đăng ký của tôi), nhưng cả hai báo cáo này đều sai. Có cách nào trong C# để làm điều này?

Trả lời

211

EDIT 2012-01-20: Oh boy! Giải pháp này đơn giản hơn rất nhiều và đã nằm trong khuôn khổ gần như mãi mãi. As pointed out by knightpfhor:

string.Compare(s1, s2, CultureInfo.CurrentCulture, CompareOptions.IgnoreNonSpace); 

Dưới đây là một chức năng mà dải dấu từ một chuỗi:

static string RemoveDiacritics(string text) 
{ 
    string formD = text.Normalize(NormalizationForm.FormD); 
    StringBuilder sb = new StringBuilder(); 

    foreach (char ch in formD) 
    { 
    UnicodeCategory uc = CharUnicodeInfo.GetUnicodeCategory(ch); 
    if (uc != UnicodeCategory.NonSpacingMark) 
    { 
     sb.Append(ch); 
    } 
    } 

    return sb.ToString().Normalize(NormalizationForm.FormC); 
} 

Chi tiết on MichKap's blog (RIP...).

Nguyên tắc là nó biến 'é' thành 2 ký tự liên tiếp 'e', ​​cấp tính. Sau đó nó lặp qua các ký tự và bỏ qua dấu phụ.

"héllo" trở thành "anh ta < cấp tính > llo", từ đó trở thành "hello".

Debug.Assert("hello"==RemoveDiacritics("héllo")); 

Lưu ý: Đây là một nhỏ gọn hơn.Net4 + thân thiện với phiên bản của chức năng tương tự:

static string RemoveDiacritics(string text) 
{ 
    return string.Concat( 
     text.Normalize(NormalizationForm.FormD) 
     .Where(ch => CharUnicodeInfo.GetUnicodeCategory(ch)!= 
            UnicodeCategory.NonSpacingMark) 
    ).Normalize(NormalizationForm.FormC); 
} 
+6

Mỗi khi tôi muốn làm điều đó, tôi kết thúc trên bài viết của bạn và tôi không bao giờ upvoted. Có thưa ngài. Đã bỏ phiếu! –

+2

Tuyệt vời. Cảm ơn rất nhiều. – Smur

+1

Cách thực hiện trong lõi .net vì nó không có 'string.Normalize'? –

-3

thử quá tải này trên Phương thức String.Compare.

String.Compare Method (String, String, Boolean, CultureInfo)

Nó tạo ra một giá trị int dựa trên các hoạt động so sánh bao gồm CultureInfo. ví dụ trong trang so sánh "Thay đổi" trong en-US và en-CZ. CH trong en-CZ là một chữ cái duy nhất.

dụ từ liên kết

using System; 
using System.Globalization; 

class Sample { 
    public static void Main() { 
    String str1 = "change"; 
    String str2 = "dollar"; 
    String relation = null; 

    relation = symbol(String.Compare(str1, str2, false, new CultureInfo("en-US"))); 
    Console.WriteLine("For en-US: {0} {1} {2}", str1, relation, str2); 

    relation = symbol(String.Compare(str1, str2, false, new CultureInfo("cs-CZ"))); 
    Console.WriteLine("For cs-CZ: {0} {1} {2}", str1, relation, str2); 
    } 

    private static String symbol(int r) { 
    String s = "="; 
    if  (r < 0) s = "<"; 
    else if (r > 0) s = ">"; 
    return s; 
    } 
} 
/* 
This example produces the following results. 
For en-US: change < dollar 
For cs-CZ: change > dollar 
*/ 

do cho các ngôn ngữ có dấu, bạn sẽ cần phải nhận được văn hóa sau đó kiểm tra các dây dựa trên đó.

http://msdn.microsoft.com/en-us/library/hyxc48dt.aspx

+0

Đây là cách tiếp cận tốt hơn so sánh trực tiếp các chuỗi, nhưng nó vẫn xem xét thư cơ sở và phiên bản có dấu * khác *. Do đó nó không trả lời câu hỏi ban đầu, mà muốn dấu trọng âm bị bỏ qua. –

6

Các phương pháp sau đây CompareIgnoreAccents(...) hoạt động trên dữ liệu ví dụ của bạn. Dưới đây là bài viết mà tôi nhận được thông tin cơ bản của tôi: http://www.codeproject.com/KB/cs/EncodingAccents.aspx

private static bool CompareIgnoreAccents(string s1, string s2) 
{ 
    return string.Compare(
     RemoveAccents(s1), RemoveAccents(s2), StringComparison.InvariantCultureIgnoreCase) == 0; 
} 

private static string RemoveAccents(string s) 
{ 
    Encoding destEncoding = Encoding.GetEncoding("iso-8859-8"); 

    return destEncoding.GetString(
     Encoding.Convert(Encoding.UTF8, destEncoding, Encoding.UTF8.GetBytes(s))); 
} 

Tôi nghĩ rằng một phương pháp mở rộng sẽ tốt hơn:

public static string RemoveAccents(this string s) 
{ 
    Encoding destEncoding = Encoding.GetEncoding("iso-8859-8"); 

    return destEncoding.GetString(
     Encoding.Convert(Encoding.UTF8, destEncoding, Encoding.UTF8.GetBytes(s))); 
} 

Sau đó, việc sử dụng sẽ là:

if(string.Compare(s1.RemoveAccents(), s2.RemoveAccents(), true) == 0) { 
    ... 
+1

điều này làm cho chữ có dấu '?' – onmyway133

+3

Đây là một so sánh phá hoại, trong đó ví dụ ā và ē sẽ được coi là bình đẳng. Bạn mất bất kỳ ký tự nào trên 0xFF và không có gì đảm bảo rằng các chuỗi đều bị bỏ qua bằng dấu trọng âm. – Abel

+0

Bạn cũng mất những thứ như ñ. Không phải là một giải pháp nếu bạn hỏi tôi. –

106

Nếu bạn không cần phải chuyển đổi chuỗi và bạn chỉ muốn kiểm tra cho bình đẳng, bạn có thể sử dụng

string s1 = "hello"; 
string s2 = "héllo"; 

if (String.Compare(s1, s2, CultureInfo.CurrentCulture, CompareOptions.IgnoreNonSpace) == 0) 
{ 
    // both strings are equal 
} 

hoặc nếu bạn muốn so sánh để cũng không phân biệt chữ hoa chữ thường

string s1 = "HEllO"; 
string s2 = "héLLo"; 

if (String.Compare(s1, s2, CultureInfo.CurrentCulture, CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase) == 0) 
{ 
    // both strings are equal 
} 
+3

100% mắt bò! –

+0

Nếu bất cứ ai khác tò mò về tùy chọn Bỏ qua không gian này, bạn có thể muốn đọc cuộc thảo luận này về nó. http://www.pcreview.co.uk/forums/accent-insensitive-t3924592.html TLDR; OK: –

+0

trên msdn: "Tiêu chuẩn Unicode định nghĩa các ký tự kết hợp làm ký tự được kết hợp với các ký tự cơ sở để tạo ra một ký tự mới. Nonspacing các ký tự kết hợp không chiếm vị trí khoảng cách khi được hiển thị." – Avlin

0

Tôi phải làm điều tương tự nhưng với phương pháp StartsWith. Đây là một giải pháp đơn giản có nguồn gốc từ @Serge - appTranslator.

Dưới đây là một phương pháp khuyến nông:

public static bool StartsWith(this string str, string value, CultureInfo culture, CompareOptions options) 
    { 
     if (str.Length >= value.Length) 
      return string.Compare(str.Substring(0, value.Length), value, culture, options) == 0; 
     else 
      return false;    
    } 

Và cho freaks một lớp lót;)

public static bool StartsWith(this string str, string value, CultureInfo culture, CompareOptions options) 
    { 
     return str.Length >= value.Length && string.Compare(str.Substring(0, value.Length), value, culture, options) == 0; 
    } 

Accent incensitive và trường hợp incensitive startsWith có thể được gọi như thế này

value.ToString().StartsWith(str, CultureInfo.InvariantCulture, CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase) 
0

Một cách đơn giản hơn để xóa dấu trọng âm:

Dim source As String = "áéíóúç" 
    Dim result As String 

    Dim bytes As Byte() = Encoding.GetEncoding("Cyrillic").GetBytes(source) 
    result = Encoding.ASCII.GetString(bytes) 
Các vấn đề liên quan