Caso insensível ‘Contém (string)’

Existe uma maneira de fazer o seguinte retornar verdadeiro?

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

Não parece haver uma sobrecarga que me permita definir a sensibilidade do case. Atualmente, eu COMPREENDO os dois, mas isso é apenas bobagem (pelo qual estou me referindo aos problemas do i18n que vêm com maiúsculas e minúsculas).

ATUALIZAR
Esta questão é antiga e, desde então, percebi que pedi uma resposta simples para um tópico realmente vasto e difícil, se você gostaria de investigá-lo completamente.
Para a maioria dos casos, em bases de código inglesas mono-linguais, esta resposta será suficiente. Estou suspeitando porque a maioria das pessoas que vem aqui se enquadram nesta categoria é a resposta mais popular.
Essa resposta, entretanto, traz à tona o problema inerente de não podermos comparar o texto a maiúsculas e minúsculas até que saibamos que ambos os textos são a mesma cultura e sabemos o que é essa cultura. Esta talvez seja uma resposta menos popular, mas acho que é mais correta e é por isso que a marquei como tal.

Para testar se o paragraph da string contém a word string (obrigado @QuarterMeister)

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

Onde culture é a instância de CultureInfo descrevendo a linguagem na qual o texto está escrito.

Essa solução é transparente sobre a definição de insensibilidade a maiúsculas e minúsculas, que é dependente de idioma . Por exemplo, o idioma inglês usa os caracteres I e i para as versões maiúsculas e minúsculas da nona letra, enquanto a língua turca usa esses caracteres para a décima primeira e décima segunda letras de seu alfabeto de 29 letras. A versão em maiúsculas do ‘i’ é o caractere desconhecido ‘İ’.

Assim, as strings tin e TIN são a mesma palavra em inglês , mas diferentes palavras em turco . Pelo que entendi, um significa “espírito” e o outro é uma palavra onomatopéia. (Turcos, por favor me corrijam se eu estiver errado, ou sugiram um exemplo melhor)

Para resumir, você só pode responder à pergunta “essas duas sequências são as mesmas, mas em casos diferentes”, se você souber em que idioma o texto está . Se você não sabe, você terá que dar uma chutada. Dada a hegemonia do inglês no software, você provavelmente deveria recorrer ao CultureInfo.InvariantCulture , porque ele estará errado de formas familiares.

Você poderia usar o método String.IndexOf e passar StringComparison.OrdinalIgnoreCase como o tipo de pesquisa a ser usada:

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

Melhor ainda é definir um novo método de extensão para string:

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

Note que essa propagação nula ?. está disponível desde C # 6.0 (VS 2015), para versões mais antigas

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

USO:

 string title = "STRING"; bool contains = title.Contains("string", StringComparison.OrdinalIgnoreCase); 

Você pode usar IndexOf() assim:

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

Como 0 (zero) pode ser um índice, você verifica contra -1.

MSDN

A posição de índice baseada em zero do valor, se essa cadeia for encontrada, ou -1, se não for. Se o valor for String.Empty, o valor de retorno será 0.

Solução alternativa usando o Regex:

 bool contains = Regex.IsMatch("StRiNG to search", "string", RegexOptions.IgnoreCase); 

Aviso prévio

Como o @cHao apontou em seu comentário, há cenários que farão com que esta solução retorne resultados incorretos. Certifique-se de que você sabe o que está fazendo antes de implementar essa solução ao acaso.

Você poderia sempre apenas aumentar ou diminuir as strings primeiro.

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

Oops, acabei de ver a última parte. Uma comparação insensível a maiúsculas * provavelmente * faria o mesmo, e se o desempenho não é um problema, não vejo problema em criar cópias em maiúsculas e compará-las. Eu poderia jurar que uma vez eu vi uma comparação insensível a maiúsculas uma vez …

Um problema com a resposta é que ele lançará uma exceção se uma string for nula. Você pode adicionar isso como um cheque para que não:

 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; } 

A class StringExtension é o caminho a seguir. Combinei algumas das postagens acima para fornecer um exemplo de código completo:

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

Isso é limpo e simples.

 Regex.IsMatch(file, fileNamestr, RegexOptions.IgnoreCase) 

OrdinalIgnoreCase, CurrentCultureIgnoreCase ou InvariantCultureIgnoreCase?

Como isso está faltando, aqui estão algumas recomendações sobre quando usar qual:

Dos

  • Use StringComparison.OrdinalIgnoreCase para comparações como seu padrão seguro para correspondência de seqüência de caracteres agnóstica de cultura.
  • Use comparações StringComparison.OrdinalIgnoreCase para aumentar a velocidade.
  • Use operações de string StringComparison.CurrentCulture-based ao exibir a saída para o usuário.
  • Alterne o uso atual de operações de cadeia de caracteres com base na cultura invariável para usar o StringComparison.Ordinal ou StringComparison.OrdinalIgnoreCase não linguístico quando a comparação for
    linguisticamente irrelevante (simbólico, por exemplo).
  • Use ToUpperInvariant vez de ToLowerInvariant ao normalizar strings para comparação.

Não é

  • Use sobrecargas para operações de cadeia de caracteres que não especificam ou implicitamente especificam o mecanismo de comparação de cadeia de caracteres.
  • Use StringComparison.InvariantCulture -based
    operações na maioria dos casos; uma das poucas exceções seria
    persistindo dados lingüisticamente significativos, mas culturalmente agnósticos.

Com base nessas regras, você deve usar:

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

enquanto [YourDecision] depende das recomendações acima.

link da fonte: http://msdn.microsoft.com/pt-br/library/ms973919.aspx

Bem assim:

 string s="AbcdEf"; if(s.ToLower().Contains("def")) { Console.WriteLine("yes"); } 

O método InStr da assembly VisualBasic é o melhor se você tiver uma preocupação com internacionalização (ou você pode reimplementá-lo). Olhando para ele, dotNeetPeek mostra que não só conta para maiúsculas e minúsculas, mas também para caracteres kana e full-versus half-width (principalmente relevantes para idiomas asiáticos, embora também existam versões de largura total do alfabeto romano ). Estou pulando alguns detalhes, mas confira o 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); } 

Eu sei que isso não é o C #, mas no quadro (VB.NET) já existe essa function

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

C # variante:

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

Usa isto:

 string.Compare("string", "STRING", new System.Globalization.CultureInfo("en-US"), System.Globalization.CompareOptions.IgnoreCase); 

Por fim, uma operação genérica “contém” se resume a uma function como essa,

 ///  /// Determines whether the source contains the sequence. ///  /// The type of the items in the sequences. /// The source enumerator. /// The sequence enumerator. /// An equality comparer. ///  /// An empty sequence will return true. /// The sequence must support  /// if it does not begin the source. ///  ///  /// true if the source contains the sequence; /// otherwise false. ///  public static bool Contains( IEnumerator sourceEnumerator, IEnumerator sequenceEnumerator, IEqualityComparer equalityComparer) { if (equalityComparer == null) { equalityComparer = EqualityComparer.Default; } while (sequenceEnumerator.MoveNext()) { if (sourceEnumerator.MoveNext()) { if (!equalityComparer.Equals( sourceEnumerator.Current, sequenceEnumerator.Current)) { sequenceEnumerator.Reset(); } } else { return false; } } return true; } 

isso pode ser trivialmente envolto em uma versão de extensão aceitando IEnumerable como este,

 public static bool Contains( this IEnumerable source, IEnumerable sequence, IEqualityComparer equalityComparer = null) { if (sequence == null) { throw new ArgumentNullException("sequence"); } using(var sequenceEnumerator = sequence.GetEnumerator()) using(var sourceEnumerator = source.GetEnumerator()) { return Contains( sourceEnumerator, sequenceEnumerator, equalityComparer); } } 

Agora, isso funcionará para a comparação ordinal de qualquer sequência, incluindo strings, já que a string implementa IEnumerable ,

 // The optional parameter ensures the generic overload is invoked // not the string.Contains() implementation. "testable".Contains("est", EqualityComparer.Default) 

No entanto, como sabemos, as strings não são genéricas, elas são especializadas. Existem dois fatores principais em jogo.

  1. A questão da “checkbox”, que por sua vez, tem vários casos de borda dependentes do idioma.
  2. A questão bastante envolvida de como um conjunto de “Elementos de Texto” (letras / números / símbolos, etc.) é representado por Pontos de Código Unicode e quais seqüências válidas de caracteres podem representar uma determinada string, os detalhes são expandidos nessas respostas .

O efeito líquido é o mesmo. As strings que você pode afirmar são linguisticamente iguais podem ser validamente representadas por diferentes combinações de caracteres. E mais, as regras de validade mudam entre culturas.

Tudo isso leva a uma string especializada com base na implementação de “Contém” como esta.

 using System.Globalization; public static bool Contains( this string source, string value, CultureInfo culture = null, CompareOptions options = CompareOptions.None) { if (value == null) { throw new ArgumentNullException("value"); } var compareInfo = culture == null ? CultureInfo.CurrentCulture.CompareInfo : culture.CompareInfo; var sourceEnumerator = StringInfo.GetTextElementEnumerator(source); var sequenceEnumerator = StringInfo.GetTextElementEnumerator(value); while (sequenceEnumerator.MoveNext()) { if (sourceEnumerator.MoveNext()) { if (!(compareInfo.Compare( sourceEnumerator.Current, sequenceEnumerator.Current, options) == 0)) { sequenceEnumerator.Reset(); } } else { return false; } } return true; } 

Essa function pode ser usada para executar uma “diferenciação” específica de maiúsculas e minúsculas que funcionará, seja qual for a normalização das cadeias. por exemplo

 "testable".Contains("EST", StringComparer.CurrentCultureIgnoreCase) 

Usando um RegEx é uma maneira direta de fazer isso:

 Regex.IsMatch(title, "string", RegexOptions.IgnoreCase); 

Isto é bastante similar ao outro exemplo aqui, mas eu decidi simplificar enum para bool, primário porque outras alternativas normalmente não são necessárias. Aqui está o meu exemplo:

 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; } } 

E o uso é algo como:

 if( "main String substring".Contains("SUBSTRING", true) ) .... 
 if ("strcmpstring1".IndexOf(Convert.ToString("strcmpstring2"), StringComparison.CurrentCultureIgnoreCase) >= 0){return true;}else{return false;} 

Você pode usar a function string.indexof () . Isso não diferencia maiúsculas de minúsculas

O truque aqui é procurar a string, ignorando o caso, mas mantê-lo exatamente igual (com o mesmo 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); 

Saída é “Reset”

Estas são as soluções mais fáceis.

  1. Por índice de

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

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

     Regex.IsMatch(title, "string", RegexOptions.IgnoreCase); 
 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; } ///  /// 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. ///  ///  /// The string to search inside. ///  ///  /// The string to seek. ///  ///  /// 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. ///  ///  /// fullText or value is null. ///  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 } 

Se você quiser verificar se sua string passada está em string, então existe um método simples para isso.

 string yourStringForCheck= "abc"; string stringInWhichWeCheck= "Test abc abc"; bool isContaines = stringInWhichWeCheck.ToLower().IndexOf(yourStringForCheck.ToLower()) > -1; This boolean value will return if string contains or not 

Maneira simples para newbie:

 title.ToLower().Contains("string");//of course "string" is lowercase.