Ignorar letras acentuadas en la comparación de cadenas

Resuelto Jon Tackabury asked hace 16 años • 6 respuestas

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?

Jon Tackabury avatar Dec 11 '08 22:12 Jon Tackabury
Aceptado

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);
}
Serge Wautier avatar Dec 15 '2008 16:12 Serge Wautier

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
}
knightpfhor avatar Oct 11 '2011 02:10 knightpfhor

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)
Guish avatar Dec 19 '2013 16:12 Guish