Não contém maiúsculas de minúsculas 'Contém (string)'

2909

Existe uma maneira de tornar o seguinte retorno verdadeiro?

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

Não parece haver uma sobrecarga que permita definir a distinção entre maiúsculas e minúsculas. Atualmente, eu supero os dois, mas isso é simplesmente bobo (pelo qual estou me referindo aos problemas da i18n que vêm com a caixa para cima e para baixo).

ATUALIZAÇÃO
Esta pergunta é antiga e, desde então, percebi que pedi uma resposta simples para um tópico realmente vasto e difícil, se você quiser investigá-lo completamente.
Para a maioria dos casos, em bases de código monolíngües e inglesas, essa resposta será suficiente. Eu suspeito que porque a maioria das pessoas que vem aqui se enquadre nessa categoria, essa é a resposta mais popular.
Essa resposta, no entanto, traz à tona o problema inerente de que não podemos comparar maiúsculas e minúsculas até que saibamos que os dois textos são da mesma cultura e sabemos o que é essa cultura. Talvez essa seja uma resposta menos popular, mas acho que é mais correta e foi por isso que a marquei como tal.

Boris Callens
fonte

Respostas:

1398

Para testar se a string paragraphcontém a string word(obrigado @QuarterMeister)

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

Onde cultureé a instância deCultureInfo descrição do idioma em que o texto está escrito.

Esta solução é transparente sobre a definição de distinção entre maiúsculas e minúsculas, que depende do idioma . Por exemplo, o idioma inglês usa os caracteres Ie ipara as versões maiúsculas e minúsculas da nona letra, enquanto o idioma turco usa esses caracteres para a décima primeira e décima segunda letras do de 29 letras. A versão em maiúscula turca de 'i' é o caractere desconhecido 'İ'.

Assim, as strings tine TINsão a mesma palavra em inglês , mas palavras diferentes em turco . Pelo que entendi, um significa "espírito" e o outro é uma palavra de onomatopéia. (Turcos, corrija-me se estiver errado ou sugira um exemplo melhor)

Para resumir, você só pode responder à pergunta 'essas duas strings são iguais, mas em casos diferentes', se souber em qual idioma o texto está . Se você não sabe, terá que dar um pontapé. Dada a hegemonia do inglês em software, você provavelmente deve recorrer CultureInfo.InvariantCulture, porque estará errado de maneiras familiares.

Coronel Panic
fonte
67
Por que não culture.CompareInfo.IndexOf(paragraph, word, CompareOptions.IgnoreCase) >= 0? Ele usa a cultura certa e não diferencia maiúsculas de minúsculas, não aloca seqüências minúsculas temporárias e evita a questão de se converter para minúsculas e comparar é sempre o mesmo que uma comparação sem distinção entre maiúsculas e minúsculas.
Quartermeister
9
Esta solução também polui desnecessariamente a pilha através da atribuição de memória para o que deveria ser uma função de busca
JaredPar
15
A comparação com ToLower () fornecerá resultados diferentes de um IndexOf que não diferencia maiúsculas de minúsculas quando duas letras diferentes têm a mesma letra minúscula. Por exemplo, chamar ToLower () em U + 0398 "Letra maiúscula grega Theta" ou U + 03F4 "Letra maiúscula grega Theta Symbol" resulta em U + 03B8, "Letra minúscula grega Theta", mas as letras maiúsculas são consideradas diferentes. Ambas as soluções consideram letras minúsculas com a mesma letra maiúscula diferente, como U + 0073 "Letra minúscula latina S" e U + 017F "Letra minúscula latina S longa", portanto a solução IndexOf parece mais consistente.
Quartermeister
3
@Quartermeister - e, BTW, acredito que o .NET 2 e o .NET4 se comportam de maneira diferente, pois o .NET 4 sempre usa NORM_LINGUISTIC_CASING enquanto o .NET 2 não (esse sinalizador apareceu no Windows Vista).
Simon Mourier 23/03
10
Por que você não escreveu "ddddfg" .IndexOf ("Df", StringComparison.OrdinalIgnoreCase)?
21415 Chen
2713

Você pode usar o método String.IndexOf e passar StringComparison.OrdinalIgnoreCasecomo o tipo de pesquisa a ser usado:

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

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

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

USO:

string title = "STRING";
bool contains = title.Contains("string", StringComparison.OrdinalIgnoreCase);
JaredPar
fonte
3
Ótimo método de extensão de string! Eu editei o meu para verificar se a string de origem não é nula para impedir que ocorram erros de referência de objeto ao executar .IndexOf ().
Richard Pursehouse
8
Isso dá a mesma resposta que paragraph.ToLower(culture).Contains(word.ToLower(culture))com CultureInfo.InvariantCulturee não resolve nenhum problema de localização. Por que complicar demais as coisas? stackoverflow.com/a/15464440/284795
Coronel Panic
60
@ColonelPanic a ToLowerversão inclui 2 alocações desnecessárias em uma operação de comparação / pesquisa. Por que alocar desnecessariamente em um cenário que não exige isso?
JaredPar
4
@Seabiscuit que não vai funcionar, porque stringé um IEnumerable<char>, portanto, você não pode usá-lo para encontrar substrings
JaredPar
6
Uma palavra de aviso: O padrão para string.IndexOf(string)é usar a cultura atual, enquanto o padrão para string.Contains(string)é usar o comparador ordinal. Como sabemos, o primeiro pode ser alterado, causando uma sobrecarga mais longa, enquanto o último não pode ser alterado. Uma conseqüência dessa inconsistência é o seguinte exemplo 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

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 com -1.

MSDN

A posição do valor com base em zero do valor, se essa sequência for encontrada, ou -1, se não for. Se o valor for String.Empty, o valor de retorno é 0.

mkchandler
fonte
148

Solução alternativa usando Regex:

bool contains = Regex.IsMatch("StRiNG to search", Regex.Escape("string"), RegexOptions.IgnoreCase);
Jed
fonte
6
Boa ideia, também temos muitas combinações bit a bit em RegexOptions, como RegexOptions.IgnoreCase & RegexOptions.IgnorePatternWhitespace & RegexOptions.CultureInvariant;para qualquer um, se ajudar.
Saravanan
7
Devo dizer que prefiro esse método, apesar de usar o IsMatch por limpeza.
Wonea
31
O que é pior: como a string de pesquisa é interpretada como uma expressão regular, vários caracteres de pontuação causarão resultados incorretos (ou acionarão uma exceção devido a uma expressão inválida). Tente procurar "."no "This is a sample string that doesn't contain the search string". Ou tente procurar "(invalid"por esse assunto.
cHao 9/09/11
17
@cHao: Nesse caso, Regex.Escapepoderia ajudar. O Regex ainda parece desnecessário quando IndexOf/ extension Containsé simples (e sem dúvida mais claro).
Dan Mangiarelli
6
Observe que eu não estava sugerindo que essa solução Regex era o melhor caminho a percorrer. Eu estava simplesmente adicionando à lista de respostas a pergunta original postada "Existe uma maneira de tornar o seguinte retorno verdadeiro?".
Jed
79

Você sempre pode subir ou baixar as strings primeiro.

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

Opa, acabei de ver essa última parte. Uma comparação sem distinção entre maiúsculas e minúsculas *provavelmente *faria o mesmo de qualquer maneira, e se o desempenho não for um problema, não vejo problema em criar cópias em maiúsculas e compará-las. Eu poderia jurar que uma vez vi uma comparação que não diferencia maiúsculas de minúsculas ...

Ed S.
fonte
122
Pesquise por "teste da Turquia" :)
Jon Skeet
7
Em algumas localidades francesas, as letras maiúsculas não têm os sinais diacríticos; portanto, ToUpper () pode não ser melhor que ToLower (). Eu diria que use as ferramentas adequadas, se estiverem disponíveis - comparação sem distinção entre maiúsculas e minúsculas.
Blair Conrad
5
Não use ToUpper ou ToLower, e fazer o que Jon Skeet disse
Peter Gfader
14
Só vi isso novamente depois de dois anos e um novo voto negativo ... de qualquer forma, concordo que existem maneiras melhores de comparar strings. No entanto, nem todos os programas serão localizados (a maioria não será) e muitos são aplicativos internos ou descartáveis. Desde que eu mal posso esperar crédito por conselhos melhores para aplicativos descartáveis ​​... Estou seguindo em frente: D
Ed S.
8
Pesquisar "Teste da Turquia" é o mesmo que pesquisar "TESTE DA TURQUIA"?
21418 JackAce
55

Somente .NET Core 2.0+ (a partir de agora)

O .NET Core possui um par de métodos para lidar com isso desde a versão 2.0:

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

Exemplo:

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

Com o tempo, eles provavelmente entrarão no .NET Standard e, a partir daí, em todas as outras implementações da Base Class Library.

Mathieu Renda
fonte
1
Agora também disponível no .NET Standard 2.1
Paweł Bulwan
52

Um problema com a resposta é que ele lançará uma exceção se uma string for nula. Você pode adicionar isso como uma verificação 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;
} 
FeiBao 飞 豹
fonte
8
Se toCheck for a string vazia, ele precisará retornar true, de acordo com a documentação Contém: "true se o parâmetro value ocorrer dentro dessa string, ou se value for a string vazia (" "); caso contrário, false."
Amurra
3
Com base no comentário de amurra acima, o código sugerido não precisa ser corrigido? E isso não deve ser adicionado à resposta aceita, para que a melhor resposta seja a primeira?
David White
13
Agora isso retornará true se source for uma string vazia ou null, não importa o que toCheck seja. Isso não pode estar correto. IndexOf também retorna true se toCheck for uma string vazia e a origem não for nula. O que é necessário aqui é uma verificação de nulo. Sugiro se (fonte == nulo || valor == nulo) retornar false;
Colin
2
A fonte não pode ser nula
Lucas
1
if (string.IsNullOrEmpty(source)) return string.IsNullOrEmpty(toCheck);
Kyle Delaney #
35

A classe StringExtension é o caminho a seguir. Combinei algumas das postagens acima para dar um exemplo 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;
    }
}
Andrew
fonte
por que você está permitindo que OUTRA camada de abstração termine StringComparison?
l
35

Isso é limpo e simples.

Regex.IsMatch(file, fileNamestr, RegexOptions.IgnoreCase)
Takirala
fonte
31
Isso irá corresponder a um padrão, no entanto. No seu exemplo, se fileNamestrtem quaisquer caracteres especiais regex (por exemplo *, +, ., etc.), então você vai estar em uma grande surpresa. A única maneira de fazer essa solução funcionar como uma Containsfunção adequada é escapar fileNamestrfazendo isso Regex.Escape(fileNamestr).
XåpplI'-I0llwlg'I - 03/02/2013
Além disso, a análise e combinando um regex é muito mais recursos do que um case-insensitive comparação simples
phuclv
29

OrdinalIgnoreCase, CurrentCultureIgnoreCase ou InvariantCultureIgnoreCase?

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

Dos

  • Usar StringComparison.OrdinalIgnoreCase para comparações como seu padrão seguro para correspondência de sequência independente de cultura.
  • Use StringComparison.OrdinalIgnoreCasecomparações para aumentar a velocidade.
  • Use StringComparison.CurrentCulture-basedoperações de cadeia 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 não-linguístico StringComparison.Ordinalou StringComparison.OrdinalIgnoreCasequando a comparação for
    linguisticamente irrelevante (simbólica, por exemplo).
  • Use em ToUpperInvariantvez de ToLowerInvariantnormalizar seqüências de caracteres para comparação.

Não é

  • Use sobrecargas para operações de cadeia que não especifiquem explícita ou implicitamente o mecanismo de comparação de cadeia.
  • Operações de StringComparison.InvariantCulturestring baseadas em uso
    na maioria dos casos; uma das poucas exceções seria a
    persistência de dados linguísticos, 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/en-us/library/ms973919.aspx

Fabian Bigler
fonte
e se você souber que sempre terá uma sequência em inglês. qual usar?
BKSpurgeon
1
@BKSpurgeon eu usaria OrdinalIgnoreCase, se o caso não importa
Fabian Bigler
20

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 maiúsculas e minúsculas

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

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

Eu sei que esse não é o C #, mas no framework (VB.NET) já existe essa função

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
fonte
11

O InStrmétodo do assembly VisualBasic é o melhor se você tiver uma preocupação com a internacionalização (ou você pode reimplementá-lo). Olhando para ele, o dotNeetPeek mostra que não apenas conta maiúsculas e minúsculas, mas também caracteres do tipo kana e caracteres de largura total vs. meia largura (principalmente relevantes para os idiomas asiáticos, embora também existam versões em 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);
}
Casey
fonte
11

Bem assim:

string s="AbcdEf";
if(s.ToLower().Contains("def"))
{
    Console.WriteLine("yes");
}
cdytoby
fonte
3
Isso não é específico da cultura e pode falhar em alguns casos. culture.CompareInfo.IndexOf (parágrafo, palavra, CompareOptions.IgnoreCase) deve ser usado.
Hikalkan
8

Usa isto:

string.Compare("string", "STRING", new System.Globalization.CultureInfo("en-US"), System.Globalization.CompareOptions.IgnoreCase);
mr.martan
fonte
26
O questionador está procurando Containsnão Compare.
DuckMaestro
@DuckMaestro, a resposta aceita está a implementar Containscom IndexOf. Portanto, essa abordagem é igualmente útil! O exemplo de código C # nesta página está usando string.Compare (). A escolha da equipe do SharePoint!
quer
6

Isso é bastante semelhante a 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) )
....
TarmoPikaro
fonte
6

Usar um RegEx é uma maneira direta de fazer isso:

Regex.IsMatch(title, "string", RegexOptions.IgnoreCase);
Stend
fonte
4
Sua resposta é exatamente igual à de guptat59, mas, como foi indicado na resposta dele, isso corresponderá a uma expressão regular; portanto, se a string que você está testando contiver caracteres especiais de regex, ela não produzirá o resultado desejado.
Casey
2
Esta é uma cópia se em linha reta de esta resposta e sofre dos mesmos problemas como observado em que a resposta
Liam
Acordado. Estude expressões regulares
Jared
5

Apenas para desenvolver a resposta aqui, você pode criar um método de extensão de string para tornar isso um pouco mais amigável:

    public static bool ContainsIgnoreCase(this string paragraph, string word)
    {
        return CultureInfo.CurrentCulture.CompareInfo.IndexOf(paragraph, word, CompareOptions.IgnoreCase) >= 0;
    }
Melbourne Developer
fonte
1
Supondo que seu parágrafo e sua palavra sempre estarão em inglês (EUA
Boris Callens
3
Para evitar problemas ao forçar a cultura a entrar nos EUA, use em seu return CultureInfo.CurrentCulture.CompareInfo.IndexOf(paragraph, word, CompareOptions.IgnoreCase) >= 0;lugar.
AndrewWhalan
3

se você quiser verificar se sua sequência passada está na sequência, existe um método simples para isso.

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

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

Este valor booleano retornará se a string estiver contida ou não

shaishav shukla
fonte
3

Tão simples e funciona

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

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

Okan SARICA
fonte
2

O truque aqui é procurar a string, ignorando maiúsculas e minúsculas, mas mantê-la exatamente a mesma (com a mesma maiúscula).

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

A saída é "Reset"

Mr.B
fonte
-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
}
Céu final
fonte
-4

Maneira simples para iniciantes:

title.ToLower().Contains("string");//of course "string" is lowercase.
O Thạnh Ldt
fonte
Downvote por apenas estar incorreto. E se title = StRiNg? StRiNg! = String e StRiNg! = STRING
berniefitz
Eu estava errado. Editar resposta da seguinte forma, simples muito simples: <br/> title.ToLower () Contém ( "string") // claro "string" é minúsculas.
O Thanh Ldt