No distingue entre mayúsculas y minúsculas 'Contiene (cadena)'

2910

¿Hay alguna manera de hacer que el siguiente retorno sea verdadero?

string title = "ASTRINGTOTEST";
title.Contains("string");

No parece haber una sobrecarga que me permita establecer la sensibilidad a mayúsculas y minúsculas. Actualmente, MAYÚSCULAS a ambos, pero eso es una tontería (por lo que me estoy refiriendo a los problemas de i18n que vienen con mayúsculas y minúsculas ).

ACTUALIZACIÓN
Esta pregunta es antigua y desde entonces me di cuenta de que pedí una respuesta simple para un tema realmente vasto y difícil si te interesa investigarlo a fondo.
Para la mayoría de los casos, en bases de código en inglés, monolingües, esta respuesta será suficiente. Sospecho que porque la mayoría de las personas que vienen aquí entran en esta categoría, esta es la respuesta más popular.
Sin embargo, esta respuesta plantea el problema inherente de que no podemos comparar las mayúsculas y minúsculas del texto hasta que sepamos que ambos textos son de la misma cultura y sabemos cuál es esa cultura. Esta es quizás una respuesta menos popular, pero creo que es más correcta y es por eso que la marqué como tal.

Boris Callens
fuente

Respuestas:

1398

Para probar si la cadena paragraphcontiene la cadena word(gracias @QuarterMeister)

culture.CompareInfo.IndexOf(paragraph, word, CompareOptions.IgnoreCase) >= 0

¿Dónde cultureestá la instancia de CultureInfodescribir el idioma en que está escrito el texto?

Esta solución es transparente sobre la definición de mayúsculas y minúsculas, que depende del idioma . Por ejemplo, el idioma inglés usa los caracteres Iy ipara las versiones en mayúsculas y minúsculas de la novena letra, mientras que el idioma turco usa estos caracteres para las letras once y doce de su alfabeto de 29 letras. La versión mayúscula turca de 'i' es el carácter desconocido 'İ'.

Por lo tanto, las cadenas tiny TINson la misma palabra en inglés , pero diferentes palabras en turco . Según tengo entendido, uno significa "espíritu" y el otro es una palabra onomatopeya. (Turcos, corríjanme si me equivoco o sugieran un mejor ejemplo)

Para resumir, solo puede responder la pregunta 'si estas dos cadenas son iguales pero en diferentes casos' si sabe en qué idioma está el texto . Si no lo sabe, tendrá que tomar un despeje. Dada la hegemonía del inglés en el software, probablemente debería recurrir CultureInfo.InvariantCulture, porque estará mal de maneras familiares.

Coronel Panic
fuente
67
¿Por qué no culture.CompareInfo.IndexOf(paragraph, word, CompareOptions.IgnoreCase) >= 0? Utiliza la cultura correcta y no distingue entre mayúsculas y minúsculas, no asigna cadenas temporales en minúsculas, y evita la pregunta de si convertir a minúsculas y comparar es siempre lo mismo que una comparación entre mayúsculas y minúsculas.
Quartermeister
99
Esta solución también contamina innecesariamente el montón asignando memoria para lo que debería ser una función de búsqueda
JaredPar
15
La comparación con ToLower () dará resultados diferentes de un IndexOf que no distingue entre mayúsculas y minúsculas cuando dos letras diferentes tienen la misma letra minúscula. Por ejemplo, llamar a ToLower () en U + 0398 "Theta mayúscula griega Theta" o U + 03F4 "Símbolo Theta mayúscula griega" da como resultado U + 03B8, "Theta minúscula griega Theta", pero las letras mayúsculas se consideran diferentes. Ambas soluciones consideran letras minúsculas con la misma letra mayúscula diferente, como U + 0073 "Letra pequeña latina S" y U + 017F "Letra pequeña latina S larga", por lo que la solución IndexOf parece más consistente.
Quartermeister
3
@Quartermeister - y por cierto, creo que .NET 2 y .NET4 se comportan de manera diferente en esto ya que .NET 4 siempre usa NORM_LINGUISTIC_CASING mientras que .NET 2 no lo hizo (estas banderas han aparecido con Windows Vista).
Simon Mourier el
10
¿Por qué no escribiste "ddddfg" .IndexOf ("Df", StringComparison.OrdinalIgnoreCase)?
Chen
2713

Puede usar el método String.IndexOf y pasarStringComparison.OrdinalIgnoreCase como el tipo de búsqueda a usar:

string title = "STRING";
bool contains = title.IndexOf("string", StringComparison.OrdinalIgnoreCase) >= 0;

Aún mejor es definir un nuevo método de extensión para la cadena:

public static class StringExtensions
{
    public static bool Contains(this string source, string toCheck, StringComparison comp)
    {
        return source?.IndexOf(toCheck, comp) >= 0;
    }
}

Tenga en cuenta que esa propagación nula ?. está disponible desde C # 6.0 (VS 2015), para versiones anteriores use

if (source == null) return false;
return source.IndexOf(toCheck, comp) >= 0;

USO:

string title = "STRING";
bool contains = title.Contains("string", StringComparison.OrdinalIgnoreCase);
JaredPar
fuente
3
Gran método de extensión de cadena! He editado el mío para verificar que la cadena de origen no sea nula para evitar que se produzcan errores de referencia de objeto al realizar .IndexOf ().
Richard Pursehouse
8
Esto da la misma respuesta que paragraph.ToLower(culture).Contains(word.ToLower(culture))con CultureInfo.InvariantCulturey no resuelve ningún problema de localización. ¿Por qué complicar más las cosas? stackoverflow.com/a/15464440/284795
Coronel Panic
6060
@ColonelPanic la ToLowerversión incluye 2 asignaciones que son innecesarias en una operación de comparación / búsqueda. ¿Por qué asignar innecesariamente en un escenario que no lo requiere?
JaredPar
44
@Seabiscuit que no va a funcionar, porque stringes una IEnumerable<char>de ahí que no se puede utilizar para buscar subcadenas
JaredPar
66
Una palabra de advertencia: el valor predeterminado para string.IndexOf(string)es usar la cultura actual, mientras que el valor predeterminado para string.Contains(string)es usar el comparador ordinal. Como sabemos, el primero se puede cambiar eligiendo una sobrecarga más larga, mientras que el segundo no se puede cambiar. Una consecuencia de esta inconsistencia es el siguiente ejemplo de código:Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; string self = "Waldstrasse"; string value = "straße"; Console.WriteLine(self.Contains(value));/* False */ Console.WriteLine(self.IndexOf(value) >= 0);/* True */
Jeppe Stig Nielsen
231

Puedes usar IndexOf()así:

string title = "STRING";

if (title.IndexOf("string", 0, StringComparison.CurrentCultureIgnoreCase) != -1)
{
    // The string exists in the original
}

Como 0 (cero) puede ser un índice, verifica con -1.

MSDN

La posición de valor de índice basada en cero si se encuentra esa cadena, o -1 si no se encuentra. Si el valor es String.Empty, el valor de retorno es 0.

mkchandler
fuente
148

Solución alternativa usando Regex:

bool contains = Regex.IsMatch("StRiNG to search", Regex.Escape("string"), RegexOptions.IgnoreCase);
Jed
fuente
66
Buena idea, también tenemos muchas combinaciones bit a bit en RegexOptions como RegexOptions.IgnoreCase & RegexOptions.IgnorePatternWhitespace & RegexOptions.CultureInvariant;para cualquier persona si ayuda.
Saravanan
77
Debo decir que prefiero este método, aunque utilizo IsMatch para la limpieza.
wonea
31
Lo que es peor, dado que la cadena de búsqueda se interpreta como una expresión regular, varios caracteres de puntuación causarán resultados incorrectos (o desencadenarán una excepción debido a una expresión no válida). Intenta buscar "."en "This is a sample string that doesn't contain the search string". O intente buscar "(invalid", para el caso.
cHao
17
@ cHao: En ese caso, Regex.Escapepodría ayudar. Regex todavía parece innecesario cuando IndexOf/ extension Containses simple (y posiblemente más claro).
Dan Mangiarelli
66
Tenga en cuenta que no estaba insinuando que esta solución Regex era la mejor manera de hacerlo. Simplemente estaba agregando a la lista de respuestas a la pregunta original publicada "¿Hay alguna manera de hacer que el siguiente retorno sea verdadero?".
Jed
79

Siempre puedes subir o bajar las cuerdas primero.

string title = "string":
title.ToUpper().Contains("STRING")  // returns true

Vaya, acabo de ver eso último. Una comparación que no distinga entre mayúsculas y minúsculas *probablemente *haría lo mismo de todos modos, y si el rendimiento no es un problema, no veo un problema al crear copias en mayúsculas y compararlas. Podría haber jurado que una vez vi una comparación entre mayúsculas y minúsculas una vez ...

Ed S.
fuente
122
Buscar "prueba de Turquía" :)
Jon Skeet
77
En algunas configuraciones regionales francesas, las letras mayúsculas no tienen los signos diacríticos, por lo que ToUpper () puede no ser mejor que ToLower (). Yo diría que use las herramientas adecuadas si están disponibles, compare las mayúsculas y minúsculas.
Blair Conrad el
55
No use ToUpper o ToLower, y haga lo que dijo Jon Skeet
Peter Gfader
14
Acabo de ver esto nuevamente después de dos años y un nuevo voto negativo ... de todos modos, estoy de acuerdo en que hay mejores formas de comparar cadenas. Sin embargo, no todos los programas serán localizados (la mayoría no) y muchos son aplicaciones internas o descartables. Ya que casi no puedo esperar crédito por el mejor consejo para las aplicaciones desechables ... Me voy a mudar: D
Ed S.
8
¿Buscar "Prueba de Turquía" es lo mismo que buscar "PRUEBA DE TURQUÍA"?
JackAce
55

.NET Core 2.0+ solamente (a partir de ahora)

.NET Core ha tenido un par de métodos para lidiar con esto desde la versión 2.0:

  • String.Contains (Char, StringComparison )
  • String.Contains (String, StringComparison )

Ejemplo:

"Test".Contains("test", System.StringComparison.CurrentCultureIgnoreCase);

Con el tiempo, probablemente llegarán al estándar .NET y, a partir de ahí, a todas las demás implementaciones de la biblioteca de clases base.

Mathieu Renda
fuente
1
Ahora también disponible en .NET Standard 2.1
Paweł Bulwan
52

Un problema con la respuesta es que arrojará una excepción si una cadena es nula. Puede agregar eso como un cheque para que no:

public static bool Contains(this string source, string toCheck, StringComparison comp)
{
    if (string.IsNullOrEmpty(toCheck) || string.IsNullOrEmpty(source))
        return true;

    return source.IndexOf(toCheck, comp) >= 0;
} 
FeiBao 飞 豹
fuente
8
Si toCheck es la cadena vacía, debe devolver verdadero según la documentación Contiene: "verdadero si el parámetro de valor se produce dentro de esta cadena, o si el valor es la cadena vacía (" "); de lo contrario, falso".
amurra
3
Según el comentario anterior de amurra, ¿no es necesario corregir el código sugerido? ¿Y no debería agregarse esto a la respuesta aceptada, para que la mejor respuesta sea la primera?
David White el
13
Ahora esto devolverá verdadero si la fuente es una cadena vacía o nula, sin importar qué verifique. Eso no puede ser correcto. También IndexOf ya devuelve verdadero si toCheck es una cadena vacía y la fuente no es nula. Lo que se necesita aquí es una comprobación de nulo. Sugiero si (fuente == nulo || valor == nulo) devuelve falso;
Colin
2
La fuente no puede ser nula
Lucas
1
if (string.IsNullOrEmpty(source)) return string.IsNullOrEmpty(toCheck);
Kyle Delaney
35

La clase StringExtension es el camino a seguir, he combinado un par de las publicaciones anteriores para dar un ejemplo de código completo:

public static class StringExtensions
{
    /// <summary>
    /// Allows case insensitive checks
    /// </summary>
    public static bool Contains(this string source, string toCheck, StringComparison comp)
    {
        return source.IndexOf(toCheck, comp) >= 0;
    }
}
Andrés
fuente
¿Por qué estás permitiendo OTRA capa de abstracción StringComparison?
l --''''''--------- '' '' '' '' '' ''
35

Esto es limpio y simple.

Regex.IsMatch(file, fileNamestr, RegexOptions.IgnoreCase)
takirala
fuente
31
Sin embargo, esto coincidirá con un patrón. En su ejemplo, si fileNamestrtiene caracteres especiales de expresiones regulares (p *. Ej +. ., Etc.), se encontrará con una gran sorpresa. La única forma de hacer que esta solución funcione como una Containsfunción adecuada es escapar fileNamestrhaciendo Regex.Escape(fileNamestr).
XåpplI'-I0llwlg'I -
además, analizar y combinar una expresión regular requiere mucho más recursos que una simple comparación entre mayúsculas y minúsculas
phuclv
29

OrdinalIgnoreCase, CurrentCultureIgnoreCase o InvariantCultureIgnoreCase?

Como esto falta, aquí hay algunas recomendaciones sobre cuándo usar cuál:

Dos

  • Utilizar StringComparison.OrdinalIgnoreCase para las comparaciones como su valor predeterminado seguro para la coincidencia de cadenas independiente de la cultura.
  • Use StringComparison.OrdinalIgnoreCasecomparaciones para aumentar la velocidad.
  • Utilizar StringComparison.CurrentCulture-based operaciones de cadena cuando muestre la salida al usuario.
  • Cambie el uso actual de las operaciones de cadena en función de la cultura invariante para usar la no lingüística StringComparison.Ordinalo StringComparison.OrdinalIgnoreCasecuando la comparación sea
    lingüísticamente irrelevante (simbólica, por ejemplo).
  • Use en ToUpperInvariantlugar de ToLowerInvariantnormalizar cadenas para comparar.

No hacer

  • Use sobrecargas para operaciones de cadenas que no especifiquen explícita o implícitamente el mecanismo de comparación de cadenas.
  • Utilice operaciones de StringComparison.InvariantCulturecadena basadas
    en la mayoría de los casos; Una de las pocas excepciones sería la
    persistencia de datos lingüísticamente significativos pero culturalmente agnósticos.

Según estas reglas, debe usar:

string title = "STRING";
if (title.IndexOf("string", 0, StringComparison.[YourDecision]) != -1)
{
    // The string exists in the original
}

mientras que [YourDecision] depende de las recomendaciones de arriba.

enlace de fuente: http://msdn.microsoft.com/en-us/library/ms973919.aspx

Fabian Bigler
fuente
¿Qué pasa si sabes que siempre vas a conseguir una cuerda en inglés? cual usar
BKSpurgeon el
1
@BKSpurgeon que haría uso de OrdinalIgnoreCase, si el caso no importa
Fabian Bigler
20

Estas son las soluciones más fáciles.

  1. Por índice de

    string title = "STRING";
    
    if (title.IndexOf("string", 0, StringComparison.CurrentCultureIgnoreCase) != -1)
    {
        // contains 
    }
  2. Al cambiar de caso

    string title = "STRING";
    
    bool contains = title.ToLower().Contains("string")
  3. Por Regex

    Regex.IsMatch(title, "string", RegexOptions.IgnoreCase);
LAV VISHWAKARMA
fuente
11

Sé que este no es el C #, pero en el marco (VB.NET) ya existe tal función

Dim str As String = "UPPERlower"
Dim b As Boolean = InStr(str, "UpperLower")

Variante C #:

string myString = "Hello World";
bool contains = Microsoft.VisualBasic.Strings.InStr(myString, "world");
serhio
fuente
11

El InStrmétodo del ensamblado VisualBasic es el mejor si le preocupa la internacionalización (o podría volver a implementarla). Al observarlo, dotNeetPeek muestra que no solo tiene en cuenta mayúsculas y minúsculas, sino también el tipo kana y los caracteres de ancho completo y medio (principalmente relevantes para los idiomas asiáticos, aunque también hay versiones de ancho completo del alfabeto romano) ) Me estoy saltando algunos detalles, pero mira el método privado InternalInStrText:

private static int InternalInStrText(int lStartPos, string sSrc, string sFind)
{
  int num = sSrc == null ? 0 : sSrc.Length;
  if (lStartPos > num || num == 0)
    return -1;
  if (sFind == null || sFind.Length == 0)
    return lStartPos;
  else
    return Utils.GetCultureInfo().CompareInfo.IndexOf(sSrc, sFind, lStartPos, CompareOptions.IgnoreCase | CompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth);
}
Casey
fuente
8

Utilizar este:

string.Compare("string", "STRING", new System.Globalization.CultureInfo("en-US"), System.Globalization.CompareOptions.IgnoreCase);
Sr.martan
fuente
26
El interrogador está buscando Containsno Compare.
DuckMaestro
@DuckMaestro, la respuesta aceptada se está implementando Containscon IndexOf. ¡Entonces este enfoque es igualmente útil! El ejemplo de código C # en esta página está usando string.Compare (). Elección del equipo de SharePoint que es!
Cuervo vulcano
6

Esto es bastante similar a otro ejemplo aquí, pero he decidido simplificar enum to bool, primario porque normalmente no se necesitan otras alternativas. Aquí está mi ejemplo:

public static class StringExtensions
{
    public static bool Contains(this string source, string toCheck, bool bCaseInsensitive )
    {
        return source.IndexOf(toCheck, bCaseInsensitive ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal) >= 0;
    }
}

Y el uso es algo como:

if( "main String substring".Contains("SUBSTRING", true) )
....
TarmoPikaro
fuente
6

Usar un RegEx es una forma directa de hacer esto:

Regex.IsMatch(title, "string", RegexOptions.IgnoreCase);
Stend
fuente
44
Su respuesta es exactamente la misma que la de guptat59, pero, como se señaló en su respuesta, coincidirá con una expresión regular, por lo que si la cadena que está probando contiene caracteres regex especiales, no obtendrá el resultado deseado.
Casey
2
Esta es una copia directa de esta respuesta y sufre los mismos problemas que se señalan en esa respuesta
Liam
Convenido. Estudie expresiones regulares
Jared
5

Solo para construir sobre la respuesta aquí, puede crear un método de extensión de cadena para que esto sea un poco más fácil de usar:

    public static bool ContainsIgnoreCase(this string paragraph, string word)
    {
        return CultureInfo.CurrentCulture.CompareInfo.IndexOf(paragraph, word, CompareOptions.IgnoreCase) >= 0;
    }
Melbourne Developer
fuente
1
Asumiendo que su párrafo y palabra siempre estarán en Estados Unidos
Boris Callens
3
Para evitar problemas al obligar a la cultura a ingresar a EE. UU., Use return CultureInfo.CurrentCulture.CompareInfo.IndexOf(paragraph, word, CompareOptions.IgnoreCase) >= 0;en su lugar.
AndrewWhalan
3

si desea verificar si su cadena pasada está en cadena, entonces hay un método simple para eso.

string yourStringForCheck= "abc";
string stringInWhichWeCheck= "Test abc abc";

bool isContained = stringInWhichWeCheck.ToLower().IndexOf(yourStringForCheck.ToLower()) > -1;

Este valor booleano devolverá si la cadena está contenida o no

shaishav shukla
fuente
3

Tan simple y funciona

title.ToLower().Contains("String".ToLower())
Pradeep Asanka
fuente
2
if ("strcmpstring1".IndexOf(Convert.ToString("strcmpstring2"), StringComparison.CurrentCultureIgnoreCase) >= 0){return true;}else{return false;}
Tamilselvan K
fuente
2

Puedes usar la string.indexof ()función. Esto será insensible a mayúsculas y minúsculas

Okan SARICA
fuente
2

El truco aquí es buscar la cadena, ignorando el caso, pero mantenerla exactamente igual (con el mismo caso).

 var s="Factory Reset";
 var txt="reset";
 int first = s.IndexOf(txt, StringComparison.InvariantCultureIgnoreCase) + txt.Length;
 var subString = s.Substring(first - txt.Length, txt.Length);

La salida es "Restablecer"

Mr.B
fuente
-1
public static class StringExtension
{
    #region Public Methods

    public static bool ExContains(this string fullText, string value)
    {
        return ExIndexOf(fullText, value) > -1;
    }

    public static bool ExEquals(this string text, string textToCompare)
    {
        return text.Equals(textToCompare, StringComparison.OrdinalIgnoreCase);
    }

    public static bool ExHasAllEquals(this string text, params string[] textArgs)
    {
        for (int index = 0; index < textArgs.Length; index++)
            if (ExEquals(text, textArgs[index]) == false) return false;
        return true;
    }

    public static bool ExHasEquals(this string text, params string[] textArgs)
    {
        for (int index = 0; index < textArgs.Length; index++)
            if (ExEquals(text, textArgs[index])) return true;
        return false;
    }

    public static bool ExHasNoEquals(this string text, params string[] textArgs)
    {
        return ExHasEquals(text, textArgs) == false;
    }

    public static bool ExHasNotAllEquals(this string text, params string[] textArgs)
    {
        for (int index = 0; index < textArgs.Length; index++)
            if (ExEquals(text, textArgs[index])) return false;
        return true;
    }

    /// <summary>
    /// Reports the zero-based index of the first occurrence of the specified string
    /// in the current System.String object using StringComparison.InvariantCultureIgnoreCase.
    /// A parameter specifies the type of search to use for the specified string.
    /// </summary>
    /// <param name="fullText">
    /// The string to search inside.
    /// </param>
    /// <param name="value">
    /// The string to seek.
    /// </param>
    /// <returns>
    /// The index position of the value parameter if that string is found, or -1 if it
    /// is not. If value is System.String.Empty, the return value is 0.
    /// </returns>
    /// <exception cref="ArgumentNullException">
    /// fullText or value is null.
    /// </exception>
    public static int ExIndexOf(this string fullText, string value)
    {
        return fullText.IndexOf(value, StringComparison.OrdinalIgnoreCase);
    }

    public static bool ExNotEquals(this string text, string textToCompare)
    {
        return ExEquals(text, textToCompare) == false;
    }

    #endregion Public Methods
}
Cielo final
fuente
-4

Manera simple para novato:

title.ToLower().Contains("string");//of course "string" is lowercase.
O Thạnh Ldt
fuente
Voto negativo por ser incorrecto. ¿Qué pasa si title = StRiNg? StRiNg! = String y StRiNg! = STRING
berniefitz
Estaba equivocado. Edite la respuesta de la siguiente manera, demasiado simple simple: <br/> title.ToLower (). Contiene ("string") // por supuesto "string" está en minúscula
O Thạnh Ldt