2008-12-11 13 views
112

Ich muss 2 Strings in C# vergleichen und akzentuierte Buchstaben genauso behandeln wie nicht akzentuierte Buchstaben. Zum Beispiel:Akzentuierte Buchstaben im String-Vergleich ignorieren

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

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

Diese 2 Strings müssen das gleiche (soweit meine Anwendung betroffen ist), aber diese beiden Aussagen falsch zu bewerten sein. Gibt es einen Weg in C#, dies zu tun?

Antwort

211

EDIT 2012-01-20: Oh Junge! Die Lösung war so viel einfacher und war fast für immer im Rahmen. As pointed out by knightpfhor:

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

Hier ist eine Funktion, die diakritischen Zeichen aus einem String-Streifen:

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

Mehr Details on MichKap's blog (RIP...).

Das Prinzip ist, dass es "é" in 2 aufeinander folgende Zeichen "e", akut wird. Es iteriert dann durch die Zeichen und überspringt die diakritischen Zeichen.

"hello" wird "er <akute> llo", die wiederum wird "Hallo".

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

Hinweis: Hier ist ein kompakter.NET4 + Version der gleichen Funktion:

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

Jedes Mal, wenn ich das machen will, lande ich auf deinem Posten und habe nie wieder abgestimmt. Es ist gut, mein Herr. Upvoted! –

+2

Ehrfürchtig. Danke vielmals. – Smur

+1

Wie geht es in .net-Core, da es nicht 'string.Normalize' hat? –

-3

versuchen Sie diese Überladung bei der String.Compare-Methode.

String.Compare Methode (String, String, Boolean, Culture)

es einen int Wert erzeugt, basierend auf den Vergleichsoperationen einschließlich Culture. Das Beispiel auf der Seite vergleicht "Change" in en-US und en-CZ. CH in en-CZ ist ein einzelner "Buchstabe".

Beispiel aus dem 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 
*/ 

dafür für akzentuierte Sprachen finden Sie die Kultur erhalten müssen dann die Saiten testen auf dieser Grundlage.

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

+0

Dies ist ein besserer Ansatz als der direkte Vergleich der Strings, aber es berücksichtigt immer noch den Basisbuchstaben und seine akzentuierte Version * anders *. Daher beantwortet es nicht die ursprüngliche Frage, nach der Akzente ignoriert werden sollten. –

6

Verfahren folgende CompareIgnoreAccents(...) auf Ihrem Beispiel Daten arbeitet. Hier ist der Artikel, wo ich meine Hintergrundinformationen bekommen: 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))); 
} 

Ich denke, eine Erweiterung Methode besser wäre:

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

Dann wird die Verwendung wäre dies:

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

dies macht Akzentbuchstaben zu "?" – onmyway133

+3

Dies ist ein destruktiver Vergleich, bei dem beispielsweise ā und ē als gleich behandelt werden. Sie verlieren alle Zeichen über 0xFF und es gibt keine Garantie, dass die Zeichenfolgen gleich ignorierende Akzente sind. – Abel

+0

Sie verlieren auch Dinge wie ñ. Keine Lösung, wenn Sie mich fragen. –

106

Wenn Sie die Zeichenfolge nicht konvertieren müssen, und Sie wollen nur für die Gleichstellung überprüfen Sie

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

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

oder wenn Sie wollen den Vergleich verwenden auch ohne Berücksichtigung der Groß- und Kleinschreibung

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% Bullauge! –

+0

Wenn sich jemand anderes für diese IgnoreNonSpace-Option interessiert, sollten Sie diese Diskussion hier lesen. http://www.pcreview.co.uk/forums/accent-insensitive-t3924592.html TLDR; es ist in Ordnung :) –

+0

auf msdn: "Der Unicode-Standard definiert die Kombination von Zeichen als Zeichen, die mit Basiszeichen kombiniert werden, um ein neues Zeichen zu erzeugen. Leerzeichen nicht kombinierende Zeichen belegen nicht eine Abstandsposition von selbst." – Avlin

0

Ich musste etwas ähnliches tun, aber mit einer StartsWith-Methode. Hier ist eine einfache Lösung, abgeleitet von @Serge - appTranslator. Hier

ist eine Erweiterung Methode:

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

Und für Einzeiler Freaks;)

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 und Fall incensitive starts kann wie dieser

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

A genannt werden einfacherer Weg, um Akzente zu entfernen:

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

    Dim bytes As Byte() = Encoding.GetEncoding("Cyrillic").GetBytes(source) 
    result = Encoding.ASCII.GetString(bytes) 
Verwandte Themen