Como verificar se uma string contém alguma de algumas strings


97

Quero verificar se uma String s contém "a" ou "b" ou "c", em C #. Estou procurando uma solução melhor do que usar

if (s.contains("a")||s.contains("b")||s.contains("c"))

1
Para casos complexos, consulte a trieestrutura de dados.
Variável miserável de

Respostas:


44

Se estiver procurando por caracteres únicos, você pode usar String.IndexOfAny().

Se você quiser strings arbitrárias, não conheço um método .NET para conseguir isso "diretamente", embora uma expressão regular funcione.


94

Bem, sempre há isto:

public static bool ContainsAny(this string haystack, params string[] needles)
{
    foreach (string needle in needles)
    {
        if (haystack.Contains(needle))
            return true;
    }

    return false;
}

Uso:

bool anyLuck = s.ContainsAny("a", "b", "c");

||No entanto, nada vai corresponder ao desempenho de sua cadeia de comparações.


12
Adicionando uma nova sintaxe curta a esta boa solução public static bool ContainsAny(this string haystack, params string[] needles) { return needles.Any(haystack.Contains); }
simonkaspers1

Solução simples e óbvia. Mas existe alguma boa implementação pronta para uso que não requeira múltiplas iterações por meio de string de palheiro? Posso implementá-lo sozinho, iterando por meio de caracteres de string de palheiro e comparando os primeiros caracteres de agulhas sequencialmente de uma vez, mas não posso acreditar que essa solução trivial ainda não foi implementada em alguma biblioteca NuGet conhecida.
RollerKostr de

@RollerKostr Não está embutido em C # (ainda), então por que adicionar dependências adicionais em seu projeto para uma solução tão simples?
jmdon de

70

Aqui está uma solução LINQ que é praticamente a mesma, mas mais escalonável:

new[] { "a", "b", "c" }.Any(c => s.Contains(c))

3
Isso é escalável no sentido de que é fácil adicionar personagens, não no sentido de performance ... :)
Guffa

2
Sim, claro. Talvez "mais extensível" fosse uma melhor escolha de palavras.
Jeff Mercado

O desempenho não será terrível. Melhor do que um regexp interpretado, de qualquer maneira.
Steven Sudit

Ótima resposta apenas para completar você pode dividir sua string de entrada em um array primeiro, por exemplo: var splitStringArray = someString.Split (''); Então você pode fazer algo como: if (someStringArray.Any (s => otherString.Contains (s))) {// do something} Espero que ajude alguém para maior clareza.
Tahir Khalid de

45
var values = new [] {"abc", "def", "ghj"};
var str = "abcedasdkljre";
values.Any(str.Contains);

21

Você pode tentar com expressão regular

string s;
Regex r = new Regex ("a|b|c");
bool containsAny = r.IsMatch (s);

1
+1, embora, como ele está procurando por caracteres únicos, uma solução linq ou indexOfAny pode ser mais eficiente.
Joel Coehoorn

+1 para a expressão regular. isso é o que eu teria escolhido, se não houvesse IndexOfAny
Stavros

1
As expressões regulares são um exagero para isso.
Steven Sudit

3
O que faz as pessoas dizerem que regexes são um exagero para isso? Se a regex for compilada uma vez e usada várias vezes, e você tiver strings com apenas c ou c perto do início e a, b perto do final, a regex seria muito mais eficiente.
bruceboughton

Não funcionou para caracteres especiais como -, '"
.`

14

Se você precisar do ContainsAny com um específico StringComparison(por exemplo, para ignorar maiúsculas e minúsculas), poderá usar este método String Extentions.

public static class StringExtensions
{
    public static bool ContainsAny(this string input, IEnumerable<string> containsKeywords, StringComparison comparisonType)
    {
        return containsKeywords.Any(keyword => input.IndexOf(keyword, comparisonType) >= 0);
    }
}

Uso com StringComparison.CurrentCultureIgnoreCase:

var input = "My STRING contains Many Substrings";
var substrings = new[] {"string", "many substrings", "not containing this string" };
input.ContainsAny(substrings, StringComparison.CurrentCultureIgnoreCase);
// The statement above returns true.

xyz”.ContainsAny(substrings, StringComparison.CurrentCultureIgnoreCase);
// This statement returns false.

2
Apenas uma nota para melhorar esta resposta. Você poderia escrever ainda mais ellegant com a palavra-chave params: ContainsAny (esta entrada de string, StringComparison compareType, params string [] containsKeywords) e use como input.ContainsAny (substrings, StringComparison.CurrentCultureIgnoreCase, "string", "muitos substrings" ... etc)
Roma Borodov

7

Esta é uma "solução mais agradável" e bastante simples

if(new string[] { "A", "B", ... }.Any(s=>myString.Contains(s)))

4

Como uma string é uma coleção de caracteres, você pode usar métodos de extensão LINQ neles:

if (s.Any(c => c == 'a' || c == 'b' || c == 'c')) ...

Isso fará a varredura da string uma vez e parará na primeira ocorrência, em vez de varrer a string uma vez para cada caractere até que uma correspondência seja encontrada.

Isso também pode ser usado para qualquer expressão que você quiser, por exemplo, verificar uma gama de caracteres:

if (s.Any(c => c >= 'a' && c <= 'c')) ...

Acordado. Isso resolve o problema de varreduras múltiplas quando as primeiras condições não correspondem. Quer saber o que é a sobrecarga do lambda? Porém, não deve ser muito.
bruceboughton

3
public static bool ContainsAny(this string haystack, IEnumerable<string> needles)
{
    return needles.Any(haystack.Contains);
}

3
List<string> includedWords = new List<string>() { "a", "b", "c" };
bool string_contains_words = includedWords.Exists(o => s.Contains(o));

2
// Nice method's name, @Dan Tao

public static bool ContainsAny(this string value, params string[] params)
{
    return params.Any(p => value.Compare(p) > 0);
    // or
    return params.Any(p => value.Contains(p));
}

Anypara qualquer, Allpara cada


2
    static void Main(string[] args)
    {
        string illegalCharacters = "!@#$%^&*()\\/{}|<>,.~`?"; //We'll call these the bad guys
        string goodUserName = "John Wesson";                   //This is a good guy. We know it. We can see it!
                                                               //But what if we want the program to make sure?
        string badUserName = "*_Wesson*_John!?";                //We can see this has one of the bad guys. Underscores not restricted.

        Console.WriteLine("goodUserName " + goodUserName +
            (!HasWantedCharacters(goodUserName, illegalCharacters) ?
            " contains no illegal characters and is valid" :      //This line is the expected result
            " contains one or more illegal characters and is invalid"));
        string captured = "";
        Console.WriteLine("badUserName " + badUserName +
            (!HasWantedCharacters(badUserName, illegalCharacters, out captured) ?
            " contains no illegal characters and is valid" :
            //We can expect this line to print and show us the bad ones
            " is invalid and contains the following illegal characters: " + captured));  

    }

    //Takes a string to check for the presence of one or more of the wanted characters within a string
    //As soon as one of the wanted characters is encountered, return true
    //This is useful if a character is required, but NOT if a specific frequency is needed
    //ie. you wouldn't use this to validate an email address
    //but could use it to make sure a username is only alphanumeric
    static bool HasWantedCharacters(string source, string wantedCharacters)
    {
        foreach(char s in source) //One by one, loop through the characters in source
        {
            foreach(char c in wantedCharacters) //One by one, loop through the wanted characters
            {
                if (c == s)  //Is the current illegalChar here in the string?
                    return true;
            }
        }
        return false;
    }

    //Overloaded version of HasWantedCharacters
    //Checks to see if any one of the wantedCharacters is contained within the source string
    //string source ~ String to test
    //string wantedCharacters ~ string of characters to check for
    static bool HasWantedCharacters(string source, string wantedCharacters, out string capturedCharacters)
    {
        capturedCharacters = ""; //Haven't found any wanted characters yet

        foreach(char s in source)
        {
            foreach(char c in wantedCharacters) //Is the current illegalChar here in the string?
            {
                if(c == s)
                {
                    if(!capturedCharacters.Contains(c.ToString()))
                        capturedCharacters += c.ToString();  //Send these characters to whoever's asking
                }
            }
        }

        if (capturedCharacters.Length > 0)  
            return true;
        else
            return false;
    }

1
Os métodos HasWantedCharacters aceitam duas ou três strings. A primeira string que queremos verificar para certos caracteres. A segunda string, todos os caracteres que procuraremos na primeira. O método sobrecarregado fornece saída para o chamador (ou seja, Main) como uma terceira string. Uma instrução foreach aninhada passa por cada caractere na origem e os compara, um por um; com aqueles personagens que estamos procurando. Se um dos caracteres for encontrado, ele retorna verdadeiro. O método sobrecarregado produz uma string de caracteres encontrados correspondentes aos verificados, mas não retornará até que todos tenham sido eliminados. Útil?
Nate Wilkins

1
Sinta-se à vontade para iniciar um projeto de console C # e copiar o código dentro da classe do programa - certifique-se de substituir o método principal. Mexa nas duas strings (goodUserName e badUserName) e você verá exatamente o que os métodos fazem e como funcionam. Os exemplos são mais longos para fornecer uma solução viável que pode ser modificada sem delimitadores como vírgulas. As sequências de escape são apenas uma maneira de representar aspas simples e barra invertida, se você precisar verificá-las.
Nate Wilkins


0

Se você estiver procurando por strings arbitrárias, e não apenas caracteres, você pode usar uma sobrecarga de IndexOfAny que pega argumentos de string do novo projeto NLib :

if (s.IndexOfAny("aaa", "bbb", "ccc", StringComparison.Ordinal) >= 0)
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.