Ignorar letras acentuadas en la comparación de cadenas
Necesito comparar 2 cadenas en C# y tratar las letras acentuadas de la misma manera que las no acentuadas. Por ejemplo:
string s1 = "hello";
string s2 = "héllo";
s1.Equals(s2, StringComparison.InvariantCultureIgnoreCase);
s1.Equals(s2, StringComparison.OrdinalIgnoreCase);
Estas 2 cadenas deben ser iguales (en lo que respecta a mi aplicación), pero ambas declaraciones se evalúan como falsas. ¿Hay alguna manera en C# de hacer esto?
FWIW, la respuesta de Knightfor a continuación (al momento de escribir este artículo) debería ser la respuesta aceptada.
Aquí hay una función que elimina los signos diacríticos de una cadena:
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);
}
Más detalles en el blog de MichKap ( QEPD... ).
El principio es que convierte 'é' en 2 caracteres sucesivos 'e', agudos. Luego recorre los caracteres y omite los signos diacríticos.
"hola" se convierte en "hola", que a su vez se convierte en "hola".
Debug.Assert("hello"==RemoveDiacritics("héllo"));
Nota: Aquí hay una versión más compacta compatible con .NET4+ de la misma función:
static string RemoveDiacritics(string text)
{
return string.Concat(
text.Normalize(NormalizationForm.FormD)
.Where(ch => CharUnicodeInfo.GetUnicodeCategory(ch)!=
UnicodeCategory.NonSpacingMark)
).Normalize(NormalizationForm.FormC);
}
Si no necesita convertir la cadena y solo desea verificar la igualdad, puede usar
string s1 = "hello";
string s2 = "héllo";
if (String.Compare(s1, s2, CultureInfo.CurrentCulture, CompareOptions.IgnoreNonSpace) == 0)
{
// both strings are equal
}
o si desea que la comparación no distinga entre mayúsculas y minúsculas también
string s1 = "HEllO";
string s2 = "héLLo";
if (String.Compare(s1, s2, CultureInfo.CurrentCulture, CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase) == 0)
{
// both strings are equal
}
Tuve que hacer algo similar pero con un método StartsWith. Aquí hay una solución simple derivada de @Serge: appTranslator.
Aquí hay un método de extensión:
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;
}
Y para los fanáticos de una sola línea;)
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;
}
El incentivo de acento y el incentivo de casos comienzan con se pueden llamar así
value.ToString().StartsWith(str, CultureInfo.InvariantCulture, CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase)