Am nevoie pentru a compara 2 siruri de caractere în C# și trata litere accentuate la fel ca non-litere accentuate. De exemplu:
string s1 = "hello";
string s2 = "héllo";
s1.Equals(s2, StringComparison.InvariantCultureIgnoreCase);
s1.Equals(s2, StringComparison.OrdinalIgnoreCase);
Aceste 2 siruri de caractere trebuie să fie același (în măsura în care cererea mea este în cauză), dar ambele afirmații evaluează la false. Există un mod în C# pentru a face acest lucru?
EDIT 2012-01-20: Oh boy! Soluția era mult mai simplă și a fost în cadrul aproape pentru totdeauna. După cum a subliniat de către knightpfhor :
string.Compare(s1, s2, CultureInfo.CurrentCulture, CompareOptions.IgnoreNonSpace);
Aici's o funcție care benzi diacritice dintr-un șir:
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);
}
Mai multe detalii pe MichKap's blog (RIP...).
Principiul este că acesta se transformă 'é' în 2 caractere succesive 'e', acute. Atunci reiterează prin caractere și sare diacritice.
"héllo" devine "a<acut>llo", care la rândul său devine "buna ziua".
Debug.Assert("hello"==RemoveDiacritics("héllo"));
Notă: Aici's-o mai compactă .NET4+ friendly versiune de aceeași funcție:
static string RemoveDiacritics(string text)
{
return string.Concat(
text.Normalize(NormalizationForm.FormD)
.Where(ch => CharUnicodeInfo.GetUnicodeCategory(ch)!=
UnicodeCategory.NonSpacingMark)
).Normalize(NormalizationForm.FormC);
}
Dacă tu nu't nevoie pentru a converti șirul și vrei doar să verificați pentru egalitatea puteți utiliza
string s1 = "hello";
string s2 = "héllo";
if (String.Compare(s1, s2, CultureInfo.CurrentCulture, CompareOptions.IgnoreNonSpace) == 0)
{
// both strings are equal
}
sau, dacă doriți o comparație a fi caz insensibil la fel de bine
string s1 = "HEllO";
string s2 = "héLLo";
if (String.Compare(s1, s2, CultureInfo.CurrentCulture, CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase) == 0)
{
// both strings are equal
}
Următoarea metodă `CompareIgnoreAccents (...) pe date exemplu. Aici este articolul unde mi-am luat informații de fond: 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)));
}
Cred că o metodă de prelungire ar fi mai bine:
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)));
}
Atunci utilizare ar fi asta:
if(string.Compare(s1.RemoveAccents(), s2.RemoveAccents(), true) == 0) {
...
Am avut de a face ceva similar, dar cu o metoda StartsWith. Aici este o soluție simplă derivat de la @Serge - appTranslator.
Aici este o metodă de prelungire:
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;
}
Și pentru unul garnituri nebuni ;)
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 și cazul incensitive startsWith poate fi numit astfel de prognoze
value.ToString().StartsWith(str, CultureInfo.InvariantCulture, CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase)
încercați această suprasarcină pe Sfoară.Compara Metoda.
Șir.Compara Metoda (String, String, Boolean, CultureInfo)
Se produce o int valoare, bazată pe compara operațiunile, inclusiv cultureinfo. de exemplu, în pagina de compara "Schimbarea" în ro-ro și ro-CZ. CH în ro-CZ este un singur "litera".
exemplu de link-ul
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
*/
pentru acestea pentru accentuate limbi veți avea nevoie pentru a obține cultura atunci testa siruri de caractere pe baza asta.