Ignorando le lettere accentate nel confronto tra stringhe

Ho bisogno di confrontare 2 stringhe in C # e trattare le lettere accentate come le lettere non accentate. Per esempio:

string s1 = "hello"; string s2 = "héllo"; s1.Equals(s2, StringComparison.InvariantCultureIgnoreCase); s1.Equals(s2, StringComparison.OrdinalIgnoreCase); 

Queste 2 stringhe devono essere le stesse (per quanto riguarda la mia applicazione), ma entrambe le affermazioni sono false. C’è un modo in C # per fare questo?

EDIT 2012-01-20: Oh ragazzo! La soluzione era molto più semplice ed è stata nel framework quasi per sempre. Come sottolineato da knightpfhor :

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

Ecco una funzione che elimina i segni diacritici da una stringa:

 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); } 

Maggiori dettagli sul blog di MichKap ( RIP … ).

Il principio è che trasforma ‘é’ in 2 caratteri successivi ‘e’, ​​acuti. Quindi itera attraverso i caratteri e salta i segni diacritici.

“héllo” diventa “he llo”, che a sua volta diventa “ciao”.

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

Nota: ecco una versione più compatta .NET4 + della stessa funzione:

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

Se non hai bisogno di convertire la stringa e vuoi solo controllare l’uguaglianza puoi usare

 string s1 = "hello"; string s2 = "héllo"; if (String.Compare(s1, s2, CultureInfo.CurrentCulture, CompareOptions.IgnoreNonSpace) == 0) { // both strings are equal } 

o se si desidera che anche il confronto sia insensibile alle maiuscole / minuscole

 string s1 = "HEllO"; string s2 = "héLLo"; if (String.Compare(s1, s2, CultureInfo.CurrentCulture, CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase) == 0) { // both strings are equal } 

Il metodo seguente CompareIgnoreAccents(...) funziona sui dati di esempio. Ecco l’articolo in cui ho ottenuto le mie informazioni di base: 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))); } 

Penso che un metodo di estensione sarebbe meglio:

 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))); } 

Quindi l’uso sarebbe questo:

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

Dovevo fare qualcosa di simile ma con un metodo StartsWith. Ecco una soluzione semplice derivata da @Serge – appTranslator.

Ecco un metodo di estensione:

  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; } 

E per gli squilibrati di una nave;)

  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; } 

Accensione incensibile e inizio caso incensibile Con questo si può chiamare così

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

Un modo più semplice per rimuovere gli accenti:

  Dim source As String = "áéíóúç" Dim result As String Dim bytes As Byte() = Encoding.GetEncoding("Cyrillic").GetBytes(source) result = Encoding.ASCII.GetString(bytes) 

prova questo sovraccarico sul metodo String.Compare.

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

Produce un valore int basato sulle operazioni di confronto, compreso cultureinfo. l’esempio nella pagina confronta “Cambia” in en-US e en-CZ. CH in en-CZ è una singola “lettera”.

esempio dal link

 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 */ 

quindi per le lingue accentate è necessario acquisire la cultura, quindi testare le stringhe in base a ciò.

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