¿Hay un operador de C # insensible a mayúsculas y minúsculas?

156

Sé que lo siguiente distingue entre mayúsculas y minúsculas:

if (StringA == StringB) {

Entonces, ¿hay un operador que compare dos cadenas de manera insensible?

GateKiller
fuente
posible duplicado de cadenas sin comparación en C #
nawfal
En caso de que alguien tropiece con esta pregunta buscando una comparación que no distinga entre mayúsculas y minúsculas para un Dictionary <string, int>, eche un vistazo a esta pregunta aquí: Acceso insensible a mayúsculas y minúsculas para diccionario genérico
Robotnik
Sería realmente lindo; digamos para definir un correspondiente ~=a paralelo ==como una versión insensible a mayúsculas y minúsculas.
eidylon
Si los desarrolladores de Microsoft ven esto, creo que es necesario un operador que no distinga entre mayúsculas y minúsculas en la próxima versión de csharp. Esta cadena. Equal () es larga.
Rez.Net

Respuestas:

288

Prueba esto:

string.Equals(a, b, StringComparison.CurrentCultureIgnoreCase);
John Feminella
fuente
Soy un novato relativo de StackOverflow. ¿Puede explicar qué quiere decir agregando un enlace? ¿Te refieres a los documentos de MSDN?
John Feminella
55
Si desea una comparación sensible a la cultura, use este método. Si solo quiere asegurarse de que "FILE" y "file" sean aceptados, use "OrdinalIgnoreCase" o su código podría no funcionar en lugares como locales turcos. Para obtener más información, visite moserware.com/2008/02/does-your-code-pass-turkey-test.html
Jeff Moser
10
No estoy seguro de qué está hablando Samuel ... esta respuesta es perfecta. Es correcto y se explica por sí mismo. No necesita referencias. +1
Vela Judo
3
¡Argh, este es un bocado horrible! mi teclado se desgastará Atrás quedaron los días en que puedo usar " if A$=B$ then goto 10"
Sanjay Manohar
9
@Sanjay Manohar Luego escriba un operador personalizado, y recomendaría un teclado mejor.
Rushyo
37

La mejor manera de comparar 2 cadenas que ignoran las mayúsculas y minúsculas es usar el método estático String.Equals que especifica una comparación ordinaria de cadenas de mayúsculas y minúsculas. Esta es también la forma más rápida, mucho más rápida que convertir las cadenas a minúsculas o mayúsculas y compararlas después de eso.

¡Probé el rendimiento de ambos enfoques y la comparación de cadena de caso de ignorar ordinal fue más de 9 veces más rápida ! También es más confiable que convertir cadenas a minúsculas o mayúsculas (consulte el problema turco i). Por lo tanto, use siempre el método String.Equals para comparar cadenas de igualdad:

String.Equals(string1, string2, StringComparison.OrdinalIgnoreCase);

Si desea realizar una comparación de cadenas específica de la cultura, puede usar el siguiente código:

String.Equals(string1, string2, StringComparison.CurrentCultureIgnoreCase);

Tenga en cuenta que el segundo ejemplo utiliza la lógica de comparación de cadenas de la cultura actual, lo que lo hace más lento que la comparación de "caso de ignorar ordinal" en el primer ejemplo, por lo que si no necesita ninguna lógica de comparación de cadenas específica de la cultura y está después del máximo rendimiento, use la comparación "ignorar el caso ordinal".

Para obtener más información, lea la historia completa en mi blog .

Pavel Vladov
fuente
1
No sugiera ToLowero ToLowerInvariant: crean memoria solo para realizar una comparación, y pueden fallar a medida que se agregan nuevos conjuntos de caracteres a Unicode. ToUpperfalla debido a la 'i' turca, entre otros; no hay razón para ToLowerque no falle en el futuro por razones similares.
antiduh
@antiduh, gracias por tu comentario. La mayoría de nosotros somos conscientes de estos posibles problemas, muchos tutoriales a través de Internet dan la 'i' turca como ejemplo. Como se puede ver en mi post, no recomendamos el uso ToLowero ToLowerInvariantmétodos, sólo quería mostrar cuánto más eficiente el String.Equalsmétodo es.
Pavel Vladov
3
"La mayoría de nosotros somos conscientes de estos posibles problemas, muchos tutoriales a través de Internet dan la 'i' turca como ejemplo", no hay suficientes personas y todavía lo mencionas como la segunda oración en tu respuesta. Además, su respuesta no incluye suficiente justificación para nunca usarla: simplemente menciona el rendimiento; El rendimiento no siempre es la máxima prioridad. Como resultado, actualmente está violando las pautas del centro de ayuda; los enlaces a sitios externos están bien, pero no ha resumido el contenido lo suficiente (problema turco "i"). SO no es su plataforma publicitaria.
antiduh
20

Hay una serie de propiedades en la StringComparerclase estática que devuelven comparadores para cualquier tipo de mayúsculas y minúsculas que desee:

StringComparer Propiedades

Por ejemplo, puedes llamar

StringComparer.CurrentCultureIgnoreCase.Equals(string1, string2)

o

StringComparer.CurrentCultureIgnoreCase.Compare(string1, string2)

Es un poco más limpio que las sobrecargas string.Equalso string.Compareque toman una StringComparisondiscusión.

Ryan Lundy
fuente
15
System.Collections.CaseInsensitiveComparer

o

System.StringComparer.OrdinalIgnoreCase
leppie
fuente
¿Esto afecta a toda la aplicación?
GateKiller
3
¿Dónde puedo encontrar más información sobre esto? ¿Esto significa que puedo usar == para una coincidencia entre mayúsculas y minúsculas?
GateKiller
9
string.Equals(StringA, StringB, StringComparison.CurrentCultureIgnoreCase);
Erick
fuente
8

o

if (StringA.Equals(StringB, StringComparison.CurrentCultureIgnoreCase)) {

pero debe asegurarse de que StringA no sea nulo. Así que probablemente sea mejor que uses:

string.Equals(StringA , StringB, StringComparison.CurrentCultureIgnoreCase);

como John sugirió

EDITAR: corrigió el error

Grzenio
fuente
4

Puedes usar

if (stringA.equals(StringB, StringComparison.CurrentCultureIgnoreCase))
Andy Mikula
fuente
3

¿Operador? NO, pero creo que puede cambiar su cultura para que la comparación de cadenas no distinga entre mayúsculas y minúsculas.

// you'll want to change this...
System.Threading.Thread.CurrentThread.CurrentCulture
// and you'll want to custimize this
System.Globalization.CultureInfo.CompareInfo

Estoy seguro de que cambiará la forma en que el operador de igualdad compara las cadenas.

John Leidegren
fuente
Sí, por decir lo menos, no es lo que querrías hacer a menos que quieras que todas las comparaciones de cadenas no distingan entre mayúsculas y minúsculas. Pero creo que cambia el comportamiento del operador igual.
John Leidegren
3

Aquí una idea para simplificar la sintaxis:

public class IgnoreCase
{
    private readonly string _value;

    public IgnoreCase(string s)
    {
        _value = s;
    }

    protected bool Equals(IgnoreCase other)
    {
        return this == other;
    }

    public override bool Equals(object obj)
    {
        return obj != null &&
               (ReferenceEquals(this, obj) || (obj.GetType() == GetType() && this == (IgnoreCase) obj));
    }

    public override int GetHashCode()
    {
        return _value?.GetHashCode() ?? 0;
    }

    public static bool operator ==(IgnoreCase a, IgnoreCase b)
    {
        return string.Equals(a, b, StringComparison.OrdinalIgnoreCase);
    }

    public static bool operator !=(IgnoreCase a, IgnoreCase b)
    {
        return !(a == b);
    }

    public static implicit operator string(IgnoreCase s)
    {
        return s._value;
    }

    public static implicit operator IgnoreCase(string s)
    {
        return new IgnoreCase(s);
    }
}

Utilizable como:

Console.WriteLine((IgnoreCase) "a" == "b"); // false
Console.WriteLine((IgnoreCase) "abc" == "abC"); // true
Console.WriteLine((IgnoreCase) "Abc" == "aBc"); // true
Console.WriteLine((IgnoreCase) "ABC" == "ABC"); // true
renouve
fuente
Si bien me gusta la sintaxis de uso de aspecto limpio , es un poco engañoso ( IgnoreCasevs IgnoreCaseString) y ambiguo (Java elige unboxing implícito vs boxeo implícito, por lo que creo que esto no funcionaría en Java con la conversión implícita de vuelta a la cadena allí). Y esto crea la sobrecarga de memoria de 2 nuevos objetos con la ejecución del árbol de llamadas para cada comparación saltando a varias llamadas a métodos anidados para el caso de uso mostrado. Dicho esto, para la mayoría de los casos, el rendimiento es probablemente lo suficientemente bueno.
Arkaine55
Si bien esta es una idea inteligente , no es realmente sabio desde una perspectiva de mantenimiento. Está creando efectivamente un tipo de cadena sustituto en lugar de usar el tipo de cadena incorporado del sistema. El programador que viene después no entenderá lo que está sucediendo de un vistazo y luego te maldecirá. Usar string.Equals () no es realmente tan malo y la mayoría de la gente entenderá lo que está haciendo.
ntcolonel
1

Estoy tan acostumbrado a escribir al final de estos métodos de comparación: , StringComparison.

Entonces hice una extensión.

namespace System
{   public static class StringExtension
    {
        public static bool Equals(this string thisString, string compareString,
             StringComparison stringComparison)
        {
            return string.Equals(thisString, compareString, stringComparison);
        }
    }
}

Solo tenga en cuenta que deberá verificar si hay nulo activado thisStringantes de llamar a la ext.

Valamas
fuente
1
¿Es esto lo mismo que este método incorporado en las versiones actuales de .NET Framework? docs.microsoft.com/en-gb/dotnet/api/…
Bernard Vander Beken el
1
Parece que sí. Parece que las versiones posteriores de .net incluyen esto ahora.
Valamas
Disponible desde .NET 4.5 y todas las versiones de .NET Core.
Bernard Vander Beken
0
string.Compare(string1, string2, true)
usuario25623
fuente
0
if (StringA.ToUpperInvariant() == StringB.ToUpperInvariant()) {

Las personas informan que ToUpperInvariant () es más rápido que ToLowerInvariant ().

knoopx
fuente
1
Invariante podría ser una mala idea si la cultura actual o deseada tiene reglas especiales para mayúsculas.
OregonGhost
¿Esto crea una nueva copia de cada cadena? Si es así, mala idea.
cjk
1
Esto también arrojará una excepción si cualquiera de las cadenas (o ambas) son nulas.
tvanfosson
3
En cuanto al rendimiento, esta no es una buena solución, ya que aquí también creará 2 nuevas instancias de cadena.
Frederik Gheysels
0

Las respuestas de otros son totalmente válidas aquí, pero de alguna manera lleva algún tiempo escribirlas StringComparison.OrdinalIgnoreCasey usarlas String.Compare.

Codifiqué un método de extensión de cadena simple, donde podría especificar si la comparación distingue entre mayúsculas y minúsculas y no tiene mayúsculas y minúsculas con boolean: consulte la siguiente respuesta:

https://stackoverflow.com/a/49208128/2338477

TarmoPikaro
fuente