2011-01-17 69 views
29

Làm cách nào để so sánh 2 chuỗi trong C# bỏ qua trường hợp, dấu cách và bất kỳ ngắt dòng nào. Tôi cũng cần phải kiểm tra xem cả hai chuỗi là null sau đó chúng được đánh dấu giống nhau.So sánh chuỗi C# bỏ qua dấu cách, chuyển dòng hoặc ngắt dòng

Cảm ơn!

+1

cũng thấy http://stackoverflow.com/questions/6859255/how-do-i-make-my-string-compare- không nhạy cảm-to-ignore-thợ mỏ-khác biệt-in-wh/6859344 # 6859344 –

+0

That khác SO câu hỏi ghi chú CompareOptions.IgnoreSymbols trên String.Compare - mà trả lời requirment này – MrTelly

Trả lời

3

Xóa tất cả các ký tự bạn không muốn và sau đó sử dụng phương thức ToLower() để bỏ qua trường hợp.

chỉnh sửa: Trong khi các công trình trên, tốt hơn là sử dụng StringComparison.OrdinalIgnoreCase. Chỉ cần chuyển nó làm đối số thứ hai cho phương thức Equals.

+22

-1: Nên sử dụng StringComparison.OrdinalIgnoreCase, không phải ToLower(). – zimdanen

+1

Sẽ không sử dụng OrdinalIgnoreCase bỏ qua văn hóa hiện tại, do đó, chạy vào (Ví dụ) vấn đề chữ hoa chữ thường i? –

+2

Phương thức với 'StringComparison.OrdinalIgnoreCase' sẽ không giải quyết được vấn đề với việc bỏ qua các dòng mới. – cederlof

4

Tôi có thể bắt đầu bằng cách xóa các ký tự bạn không muốn so sánh khỏi chuỗi trước khi so sánh. Nếu hiệu suất là một mối quan tâm, bạn có thể xem xét lưu trữ một phiên bản của mỗi chuỗi với các ký tự đã bị xóa.

Hoặc, bạn có thể viết thói quen so sánh sẽ bỏ qua các ký tự bạn muốn bỏ qua. Nhưng điều đó dường như có nhiều công việc hơn với tôi.

+0

+1 http://msdn.microsoft.com /en-us/library/aa904305(VS.71).aspx, sau đó http://msdn.microsoft.com/en-us/library/system.string.join.aspx và so sánh. – kenny

59

Bạn nên chuẩn hóa từng chuỗi bằng cách xóa các ký tự mà bạn không muốn so sánh và sau đó bạn có thể thực hiện String.Equals với một số StringComparison bỏ qua trường hợp.

Something như thế này:

string s1 = "HeLLo wOrld!"; 
string s2 = "Hello\n WORLd!"; 

string normalized1 = Regex.Replace(s1, @"\s", ""); 
string normalized2 = Regex.Replace(s2, @"\s", ""); 

bool stringEquals = String.Equals(
    normalized1, 
    normalized2, 
    StringComparison.OrdinalIgnoreCase); 

Console.WriteLine(stringEquals); 

Đây Regex.Replace được sử dụng đầu tiên để loại bỏ tất cả các ký tự khoảng trắng. Trường hợp đặc biệt của cả hai chuỗi là null không được xử lý ở đây nhưng bạn có thể dễ dàng xử lý trường hợp đó trước khi thực hiện chuẩn hóa chuỗi.

+0

Có bất kỳ tác động hiệu suất nào không khi sử dụng 'Regex.Replace' trên hai chuỗi ở đây? – JDandChips

+0

Đó là điều không dễ giải đáp. Tất nhiên có giải pháp tốt hơn về hiệu suất, ví dụ giải pháp không yêu cầu tạo hai chuỗi mới nhưng trừ khi bạn chứng minh rằng cụm từ thông dụng là nút cổ chai trong kịch bản cụ thể của bạn thì tôi sẽ không bận tâm đến nó. –

3

Đầu tiên thay thế tất cả khoảng trống thông qua biểu thức chính quy từ cả hai chuỗi và sau đó sử dụng phương thức String.Compare với tham số ignoreCase = true.

string a = System.Text.RegularExpressions.Regex.Replace("void foo", @"\s", ""); 
string b = System.Text.RegularExpressions.Regex.Replace("voidFoo", @"\s", ""); 
bool isTheSame = String.Compare(a, b, true) == 0; 
-2

Hãy thử sử dụng này thay vào đó, nó sạch hơn và mất nó từ hệ điều hành mà bạn đang sử dụng:

Environment.NewLine

+0

Đối với những gì, và thay vì những gì? –

0

Bạn cũng có thể sử dụng chức năng tùy chỉnh sau

public static string ExceptChars(this string str, IEnumerable<char> toExclude) 
     { 
      StringBuilder sb = new StringBuilder(); 
      for (int i = 0; i < str.Length; i++) 
      { 
       char c = str[i]; 
       if (!toExclude.Contains(c)) 
        sb.Append(c); 
      } 
      return sb.ToString(); 
     } 

     public static bool SpaceCaseInsenstiveComparision(this string stringa, string stringb) 
     { 
      return (stringa==null&&stringb==null)||stringa.ToLower().ExceptChars(new[] { ' ', '\t', '\n', '\r' }).Equals(stringb.ToLower().ExceptChars(new[] { ' ', '\t', '\n', '\r' })); 
     } 

Và sau đó sử dụng nó theo cách

"Te st".SpaceCaseInsenstiveComparision("Te st"); 
+1

Tôi muốn tránh các cuộc gọi '.ToLower()' (vì chúng tạo ra một chuỗi khác) và sử dụng 'StringComparison.OrdinalIgnoreCase' (cũng nhanh hơn). –

3

Nếu bạn cần hiệu suất, các giải pháp Regex trên trang này chạy quá chậm cho bạn. Có thể bạn có một danh sách lớn các chuỗi bạn muốn sắp xếp. (Tuy nhiên, giải pháp Regex dễ đọc hơn)

Tôi có một lớp xem xét từng char riêng biệt trong cả hai chuỗi và so sánh chúng trong khi bỏ qua trường hợp và khoảng trắng. Nó không phân bổ bất kỳ chuỗi mới nào. Nó sử dụng char.IsWhiteSpace(ch) để xác định khoảng trắng và char.ToLowerInvariant(ch) cho trường hợp không nhạy cảm (nếu được yêu cầu). Trong thử nghiệm của tôi, giải pháp của tôi chạy nhanh hơn 5x - 8x so với giải pháp dựa trên Regex. Lớp của tôi cũng thực hiện phương thức GetHashCode(obj) của IEqualityComparer bằng cách sử dụng this code trong một câu trả lời SO khác. Điều này GetHashCode(obj) cũng bỏ qua khoảng trắng và tùy chọn bỏ qua trường hợp.

Đây là lớp học của tôi:

private class StringCompIgnoreWhiteSpace : IEqualityComparer<string> 
{ 
    public bool Equals(string strx, string stry) 
    { 
     if (strx == null) //stry may contain only whitespace 
      return string.IsNullOrWhiteSpace(stry); 

     else if (stry == null) //strx may contain only whitespace 
      return string.IsNullOrWhiteSpace(strx); 

     int ix = 0, iy = 0; 
     for (; ix < strx.Length && iy < stry.Length; ix++, iy++) 
     { 
      char chx = strx[ix]; 
      char chy = stry[iy]; 

      //ignore whitespace in strx 
      while (char.IsWhiteSpace(chx) && ix < strx.Length) 
      { 
       ix++; 
       chx = strx[ix]; 
      } 

      //ignore whitespace in stry 
      while (char.IsWhiteSpace(chy) && iy < stry.Length) 
      { 
       iy++; 
       chy = stry[iy]; 
      } 

      if (ix == strx.Length && iy != stry.Length) 
      { //end of strx, so check if the rest of stry is whitespace 
       for (int iiy = iy + 1; iiy < stry.Length; iiy++) 
       { 
        if (!char.IsWhiteSpace(stry[iiy])) 
         return false; 
       } 
       return true; 
      } 

      if (ix != strx.Length && iy == stry.Length) 
      { //end of stry, so check if the rest of strx is whitespace 
       for (int iix = ix + 1; iix < strx.Length; iix++) 
       { 
        if (!char.IsWhiteSpace(strx[iix])) 
         return false; 
       } 
       return true; 
      } 

      //The current chars are not whitespace, so check that they're equal (case-insensitive) 
      //Remove the following two lines to make the comparison case-sensitive. 
      chx = char.ToLowerInvariant(chx); 
      chy = char.ToLowerInvariant(chy); 

      if (chx != chy) 
       return false; 
     } 

     //If strx has more chars than stry 
     for (; ix < strx.Length; ix++) 
     { 
      if (!char.IsWhiteSpace(strx[ix])) 
       return false; 
     } 

     //If stry has more chars than strx 
     for (; iy < stry.Length; iy++) 
     { 
      if (!char.IsWhiteSpace(stry[iy])) 
       return false; 
     } 

     return true; 
    } 

    public int GetHashCode(string obj) 
    { 
     if (obj == null) 
      return 0; 

     int hash = 17; 
     unchecked // Overflow is fine, just wrap 
     { 
      for (int i = 0; i < obj.Length; i++) 
      { 
       char ch = obj[i]; 
       if(!char.IsWhiteSpace(ch)) 
        //use this line for case-insensitivity 
        hash = hash * 23 + char.ToLowerInvariant(ch).GetHashCode(); 

        //use this line for case-sensitivity 
        //hash = hash * 23 + ch.GetHashCode(); 
      } 
     } 
     return hash; 
    } 
} 

private static void TestComp() 
{ 
    var comp = new StringCompIgnoreWhiteSpace(); 

    Console.WriteLine(comp.Equals("abcd", "abcd")); //true 
    Console.WriteLine(comp.Equals("abCd", "Abcd")); //true 
    Console.WriteLine(comp.Equals("ab Cd", "Ab\n\r\tcd ")); //true 
    Console.WriteLine(comp.Equals(" ab Cd", " A b" + Environment.NewLine + "cd ")); //true 
    Console.WriteLine(comp.Equals(null, " \t\n\r ")); //true 
    Console.WriteLine(comp.Equals(" \t\n\r ", null)); //true 
    Console.WriteLine(comp.Equals("abcd", "abcd h")); //false 

    Console.WriteLine(comp.GetHashCode(" a b c d")); //-699568861 


    //This is -699568861 if you #define StringCompIgnoreWhiteSpace_CASE_INSENSITIVE 
    // Otherwise it's -1555613149 
    Console.WriteLine(comp.GetHashCode("A B c  \t  d")); 
} 

Đây là mã thử nghiệm của tôi (với một ví dụ Regex):

private static void SpeedTest() 
{ 
    const int loop = 100000; 
    string first = "a bc d"; 
    string second = "ABC D"; 

    var compChar = new StringCompIgnoreWhiteSpace(); 
    Stopwatch sw1 = Stopwatch.StartNew(); 
    for (int i = 0; i < loop; i++) 
    { 
     bool equals = compChar.Equals(first, second); 
    } 
    sw1.Stop(); 
    Console.WriteLine(string.Format("char time = {0}", sw1.Elapsed)); //char time = 00:00:00.0361159 

    var compRegex = new StringCompIgnoreWhiteSpaceRegex(); 
    Stopwatch sw2 = Stopwatch.StartNew(); 
    for (int i = 0; i < loop; i++) 
    { 
     bool equals = compRegex.Equals(first, second); 
    } 
    sw2.Stop(); 
    Console.WriteLine(string.Format("regex time = {0}", sw2.Elapsed)); //regex time = 00:00:00.2773072 
} 

private class StringCompIgnoreWhiteSpaceRegex : IEqualityComparer<string> 
{ 
    public bool Equals(string strx, string stry) 
    { 
     if (strx == null) 
      return string.IsNullOrWhiteSpace(stry); 
     else if (stry == null) 
      return string.IsNullOrWhiteSpace(strx); 

     string a = System.Text.RegularExpressions.Regex.Replace(strx, @"\s", ""); 
     string b = System.Text.RegularExpressions.Regex.Replace(stry, @"\s", ""); 
     return String.Compare(a, b, true) == 0; 
    } 

    public int GetHashCode(string obj) 
    { 
     if (obj == null) 
      return 0; 

     string a = System.Text.RegularExpressions.Regex.Replace(obj, @"\s", ""); 
     return a.GetHashCode(); 
    } 
} 
0

Một lựa chọn khác là LINQ SequenceEquals phương pháp mà theo các bài kiểm tra của tôi nhanh gấp hai lần ông Regex tiếp cận được sử dụng trong các câu trả lời khác và rất dễ đọc và duy trì.

public static bool Equals_Linq(string s1, string s2) 
{ 
    return Enumerable.SequenceEqual(
     s1.Where(c => !char.IsWhiteSpace(c)).Select(char.ToUpperInvariant), 
     s2.Where(c => !char.IsWhiteSpace(c)).Select(char.ToUpperInvariant)); 
} 

public static bool Equals_Regex(string s1, string s2) 
{ 
    return string.Equals(
     Regex.Replace(s1, @"\s", ""), 
     Regex.Replace(s2, @"\s", ""), 
     StringComparison.OrdinalIgnoreCase); 
} 

Ở đây mã kiểm tra hiệu suất đơn giản tôi đã sử dụng:

var s1 = "HeLLo wOrld!"; 
var s2 = "Hello\n WORLd!"; 
var watch = Stopwatch.StartNew(); 
for (var i = 0; i < 1000000; i++) 
{ 
    Equals_Linq(s1, s2); 
} 
Console.WriteLine(watch.Elapsed); // ~1.7 seconds 
watch = Stopwatch.StartNew(); 
for (var i = 0; i < 1000000; i++) 
{ 
    Equals_Regex(s1, s2); 
} 
Console.WriteLine(watch.Elapsed); // ~4.6 seconds 
Các vấn đề liên quan