Cómo comprobar si una cadena contiene alguna de algunas cadenas


98

Quiero comprobar si un String s, contiene "a" o "b" o "c", en C #. Estoy buscando una mejor solución que usar

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

1
Para casos complejos, busque triela estructura de datos.
Variable Miserable

Respuestas:


44

Si está buscando caracteres individuales, puede usar String.IndexOfAny().

Si desea cadenas arbitrarias, entonces no conozco un método .NET para lograr eso "directamente", aunque una expresión regular funcionaría.


94

Bueno, siempre hay esto:

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

||Sin embargo, nada va a igualar el rendimiento de su cadena de comparaciones.


12
Añadiendo una nueva sintaxis corta a esta buena solución public static bool ContainsAny(this string haystack, params string[] needles) { return needles.Any(haystack.Contains); }
simonkaspers1

Solución simple y obvia. Pero, ¿hay alguna buena implementación lista para usar que no requiera múltiples iteraciones a través de una cadena de pajar? Puedo implementarlo por mí mismo, iterando a través de caracteres de cadena de pajar y comparando los primeros caracteres de las agujas secuencialmente de una vez, pero no puedo creer que una solución tan trivial aún no se haya implementado en alguna biblioteca NuGet conocida.
RollerKostr

@RollerKostr No está integrado en C # (todavía), así que ¿por qué agregar dependencias adicionales en su proyecto para una solución tan simple?
jmdon

70

Aquí hay una solución LINQ que es prácticamente la misma pero más escalable:

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

3
Eso es escalable en el sentido de que es fácil agregar caracteres, no en el sentido de rendimiento ... :)
Guffa

2
Ah, sí, por supuesto. Quizás "más extensible" hubiera sido una mejor elección de palabras.
Jeff Mercado

La actuación no será terrible. Mejor que una expresión regular interpretada, de todos modos.
Steven Sudit

Respuesta impresionante solo para completar, puede dividir su cadena entrante en una matriz primero, por ejemplo: var splitStringArray = someString.Split (''); Entonces puedes hacer algo como: if (someStringArray.Any (s => otherString.Contains (s))) {// haz algo} Espero que ayude a alguien a tener claridad.
Tahir Khalid

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

21

Puedes probar con expresiones regulares

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

1
+1, aunque como está buscando caracteres individuales, una solución de linq o indexOfAny podría ser más eficiente.
Joel Coehoorn

+1 para la expresión regular. eso es lo que habría buscado, si no hubiera IndexOfAny
Stavros

1
Las expresiones regulares son excesivas para esto.
Steven Sudit

3
¿Qué hace que la gente diga que las expresiones regulares son excesivas para esto? Si la expresión regular se compila una vez y se usa varias veces, y tiene cadenas con solo c en ellas oc cerca del principio y a, b cerca del final, la expresión regular sería mucho más eficiente.
bruceboughton

No funcionó para caracteres especiales como -, '"
.`

15

Si necesita ContainsAny con un específico StringComparison(por ejemplo, para ignorar mayúsculas y minúsculas), puede 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 con 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.

3
Solo una nota para mejorar esta respuesta. Podría escribirlo aún más elegante con la palabra clave params: ContainsAny (esta cadena input, StringComparison compareType, params string [] containsKeywords) y usar como input.ContainsAny (substrings, StringComparison.CurrentCultureIgnoreCase, "string", "muchas subcadenas" ... etc)
Roma Borodov

7

Esta es una "mejor solución" y bastante simple

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

4

Como una cadena es una colección de caracteres, puede usar métodos de extensión LINQ en ellos:

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

Esto escaneará la cadena una vez y se detendrá en la primera aparición, en lugar de escanear la cadena una vez para cada carácter hasta que se encuentre una coincidencia.

Esto también se puede usar para cualquier expresión que desee, por ejemplo, para verificar un rango de caracteres:

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

Convenido. Esto resuelve el problema de varios escaneos cuando las primeras condiciones no coinciden. ¿Me pregunto cuál es la sobrecarga del lambda? Sin embargo, no debería ser mucho una vez.
bruceboughton

4
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 cualquiera, 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
Los métodos HasWantedCharacters aceptan dos o tres cadenas. La primera cadena que queremos verificar para ciertos caracteres. La segunda cadena, todos los caracteres que buscaremos en la primera. El método sobrecargado proporciona salida a la persona que llama (es decir, Main) como una tercera cadena. Una instrucción foreach anidada pasa por cada carácter en la fuente y los compara, uno por uno; con esos personajes que estamos buscando. Si se encuentra uno de los caracteres, devuelve verdadero. El método sobrecargado genera una cadena de caracteres que coinciden con los marcados, pero no regresará hasta que todos estén fuera. ¿Servicial?
Nate Wilkins

1
Siéntase libre de iniciar un proyecto de consola C # y copiar el código dentro de la clase del programa; asegúrese de reemplazar el método principal. Juega con las dos cadenas (goodUserName y badUserName) y es posible que veas qué hacen los métodos y cómo funcionan. Los ejemplos son más largos para proporcionar una solución viable que se puede modificar sin delimitadores como comas. Las secuencias de escape son solo una forma de representar las comillas simples y la barra invertida si necesita verificarlas.
Nate Wilkins


0

Si está buscando cadenas arbitrarias, y no solo caracteres, puede usar una sobrecarga de IndexOfAny que toma argumentos de cadena del nuevo proyecto NLib :

if (s.IndexOfAny("aaa", "bbb", "ccc", StringComparison.Ordinal) >= 0)
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.