Compruebe si una cadena contiene una cadena en C ++


494

Tengo una variable de tipo std::string. Quiero verificar si contiene un cierto std::string. ¿Como podría hacerlo?

¿Hay una función que devuelve verdadero si se encuentra la cadena y falso si no lo es?


66
¿Te refieres a char * string o al string del STL?
anthares

1
No es una cadena char *. Tuve que #incluir <cadena> para usarlo.
neuromancer

1
Algunas de las soluciones están usando s2 para la cadena que quiero encontrar. ¿Funcionará si uso algo como "esto es una cadena" en lugar de s2?
neuromántico

2
Sí, porque hay un constructor de cadena literl para el tipo std :: string.

18
Alguien haga una propuesta para agregar std::basic_string::containsa la stdlib.
Emlai

Respuestas:


723

Use de la std::string::findsiguiente manera:

if (s1.find(s2) != std::string::npos) {
    std::cout << "found!" << '\n';
}

Nota: "encontrado" se imprimirá si s2es una subcadena de s1, ambos s1y s2son de tipo std::string.


117

Puedes intentar usar la findfunción:

string str ("There are two needles in this haystack.");
string str2 ("needle");

if (str.find(str2) != string::npos) {
//.. found.
} 

27

En realidad, puede intentar usar la biblioteca boost, creo que std :: string no proporciona el método suficiente para hacer todas las operaciones de cadena comunes. En boost, puede usar el boost::algorithm::contains:

#include <string>
#include <boost/algorithm/string.hpp>

int main() {
    std::string s("gengjiawen");
    std::string t("geng");
    bool b = boost::algorithm::contains(s, t);
    std::cout << b << std::endl;
    return 0;
}

33
"Creo que std :: string no proporciona suficiente método para hacer todas las operaciones de cadena comunes". Pero hay un findmétodo para exactamente la tarea en cuestión. No es necesario introducir una dependencia de biblioteca.
stefan

8
@stefan, tienes razón, hay un método de búsqueda, pero ¿qué hay de dividir, reemplazar y muchos otros miembros del personal? Puedes comparar std :: string con la api de cadena en Java. PS: También creo que contiene es mucho más elegante que buscar para verificar si una cadena contiene otra cadena.
Geng Jiawen

1
Además, esto es corto y más fácil de memorizar. Cpp 17 tiene soporte adicional para el sistema de archivos. Espero que Cpp 2x también haga algo para la cadena. Es muy doloroso la falta de soporte básico del método de cadena en cpp moderno.
Geng Jiawen

1
¿Realmente necesitas los "usos"? Cuando leo este código, no tengo idea de si containses std::containso boost::contains, lo que parece un inconveniente significativo. Supongo que std :: contiene no existe actualmente, pero no estoy seguro de que sea razonable suponer que el lector ha memorizado todo lo que está en std. Y bien std::containspodría existir en alguna versión futura de c ++, lo que rompería este programa.
Don Hatch

12

Puedes probar esto

string s1 = "Hello";
string s2 = "el";
if(strstr(s1.c_str(),s2.c_str()))
{
   cout << " S1 Contains S2";
}

4

En el caso de que la funcionalidad sea crítica para su sistema, en realidad es beneficioso usar un strstrmétodo antiguo . El std::searchmétodo dentro algorithmes el más lento posible. Supongo que tomará mucho tiempo crear esos iteradores.

El código que solía cronometrar todo es

#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <random>
#include <chrono>

std::string randomString( size_t len );

int main(int argc, char* argv[])
{
        using namespace std::chrono;

        const size_t haystacksCount = 200000;
        std::string haystacks[haystacksCount];
        std::string needle = "hello";

        bool sink = true;

        high_resolution_clock::time_point start, end;
        duration<double> timespan;

        int sizes[10] = { 10, 20, 40, 80, 160, 320, 640, 1280, 5120, 10240 };

        for(int s=0; s<10; ++s)
        {
                std::cout << std::endl << "Generating " << haystacksCount << " random haystacks of size " << sizes[s] << std::endl;
                for(size_t i=0; i<haystacksCount; ++i)
                {
                        haystacks[i] = randomString(sizes[s]);
                }

                std::cout << "Starting std::string.find approach" << std::endl;
                start = high_resolution_clock::now();
                for(size_t i=0; i<haystacksCount; ++i)
                {
                        if(haystacks[i].find(needle) != std::string::npos)
                        {
                                sink = !sink; // useless action
                        }
                }
                end = high_resolution_clock::now();
                timespan = duration_cast<duration<double>>(end-start);
                std::cout << "Processing of " << haystacksCount << " elements took " << timespan.count() << " seconds." << std::endl;

                std::cout << "Starting strstr approach" << std::endl;
                start = high_resolution_clock::now();
                for(size_t i=0; i<haystacksCount; ++i)
                {
                        if(strstr(haystacks[i].c_str(), needle.c_str()))
                        {
                                sink = !sink; // useless action
                        }
                }
                end = high_resolution_clock::now();
                timespan = duration_cast<duration<double>>(end-start);
                std::cout << "Processing of " << haystacksCount << " elements took " << timespan.count() << " seconds." << std::endl;

                std::cout << "Starting std::search approach" << std::endl;
                start = high_resolution_clock::now();
                for(size_t i=0; i<haystacksCount; ++i)
                {
                        if(std::search(haystacks[i].begin(), haystacks[i].end(), needle.begin(), needle.end()) != haystacks[i].end())
                        {
                                sink = !sink; // useless action
                        }
                }
                end = high_resolution_clock::now();
                timespan = duration_cast<duration<double>>(end-start);
                std::cout << "Processing of " << haystacksCount << " elements took " << timespan.count() << " seconds." << std::endl;
        }

        return 0;
}

std::string randomString( size_t len)
{
        static const char charset[] = "abcdefghijklmnopqrstuvwxyz";
        static const int charsetLen = sizeof(charset) - 1;
        static std::default_random_engine rng(std::random_device{}());
        static std::uniform_int_distribution<> dist(0, charsetLen);
        auto randChar = [charset, &dist, &rng]() -> char
        {
                return charset[ dist(rng) ];
        };

        std::string result(len, 0);
        std::generate_n(result.begin(), len, randChar);
        return result;
}

Aquí genero al azar haystacksy busco en ellos el needle. El recuento de pajar se establece, pero la longitud de las cadenas dentro de cada pajar aumenta de 10 al principio a 10240 al final. La mayoría de las veces el programa gasta realmente la generación de cadenas aleatorias, pero eso es de esperarse.

El resultado es:

Generating 200000 random haystacks of size 10
Starting std::string.find approach
Processing of 200000 elements took 0.00358503 seconds.
Starting strstr approach
Processing of 200000 elements took 0.0022727 seconds.
Starting std::search approach
Processing of 200000 elements took 0.0346258 seconds.

Generating 200000 random haystacks of size 20
Starting std::string.find approach
Processing of 200000 elements took 0.00480959 seconds.
Starting strstr approach
Processing of 200000 elements took 0.00236199 seconds.
Starting std::search approach
Processing of 200000 elements took 0.0586416 seconds.

Generating 200000 random haystacks of size 40
Starting std::string.find approach
Processing of 200000 elements took 0.0082571 seconds.
Starting strstr approach
Processing of 200000 elements took 0.00341435 seconds.
Starting std::search approach
Processing of 200000 elements took 0.0952996 seconds.

Generating 200000 random haystacks of size 80
Starting std::string.find approach
Processing of 200000 elements took 0.0148288 seconds.
Starting strstr approach
Processing of 200000 elements took 0.00399263 seconds.
Starting std::search approach
Processing of 200000 elements took 0.175945 seconds.

Generating 200000 random haystacks of size 160
Starting std::string.find approach
Processing of 200000 elements took 0.0293496 seconds.
Starting strstr approach
Processing of 200000 elements took 0.00504251 seconds.
Starting std::search approach
Processing of 200000 elements took 0.343452 seconds.

Generating 200000 random haystacks of size 320
Starting std::string.find approach
Processing of 200000 elements took 0.0522893 seconds.
Starting strstr approach
Processing of 200000 elements took 0.00850485 seconds.
Starting std::search approach
Processing of 200000 elements took 0.64133 seconds.

Generating 200000 random haystacks of size 640
Starting std::string.find approach
Processing of 200000 elements took 0.102082 seconds.
Starting strstr approach
Processing of 200000 elements took 0.00925799 seconds.
Starting std::search approach
Processing of 200000 elements took 1.26321 seconds.

Generating 200000 random haystacks of size 1280
Starting std::string.find approach
Processing of 200000 elements took 0.208057 seconds.
Starting strstr approach
Processing of 200000 elements took 0.0105039 seconds.
Starting std::search approach
Processing of 200000 elements took 2.57404 seconds.

Generating 200000 random haystacks of size 5120
Starting std::string.find approach
Processing of 200000 elements took 0.798496 seconds.
Starting strstr approach
Processing of 200000 elements took 0.0137969 seconds.
Starting std::search approach
Processing of 200000 elements took 10.3573 seconds.

Generating 200000 random haystacks of size 10240
Starting std::string.find approach
Processing of 200000 elements took 1.58171 seconds.
Starting strstr approach
Processing of 200000 elements took 0.0143111 seconds.
Starting std::search approach
Processing of 200000 elements took 20.4163 seconds.

La versión más corta de la respuesta es: usar c en lugar de c ++ :)
r0ng

3

Si no desea utilizar las funciones estándar de la biblioteca, a continuación encontrará una solución.

#include <iostream>
#include <string>

bool CheckSubstring(std::string firstString, std::string secondString){
    if(secondString.size() > firstString.size())
        return false;

    for (int i = 0; i < firstString.size(); i++){
        int j = 0;
        // If the first characters match
        if(firstString[i] == secondString[j]){
            int k = i;
            while (firstString[i] == secondString[j] && j < secondString.size()){
                j++;
                i++;
            }
            if (j == secondString.size())
                return true;
            else // Re-initialize i to its original value
                i = k;
        }
    }
    return false;
}

int main(){
    std::string firstString, secondString;

    std::cout << "Enter first string:";
    std::getline(std::cin, firstString);

    std::cout << "Enter second string:";
    std::getline(std::cin, secondString);

    if(CheckSubstring(firstString, secondString))
        std::cout << "Second string is a substring of the frist string.\n";
    else
        std::cout << "Second string is not a substring of the first string.\n";

    return 0;
}

66
Ya está utilizando std :: string, por lo tanto, su código ya depende de std lib. Realmente no veo ninguna razón para evitar la solución aceptada usando std :: string :: find.
b00n12

Sí, ese es un buen punto. No pensé eso cuando escribí esto. Supongo que lo que pensé cuando escribí esto fue quizás cómo evitar usar std :: find.
Testing123

3
Solo para futuros visitantes: este algoritmo no es realmente correcto. Debido a que "i" nunca regresa después de una coincidencia de subcadena fallida, algunos casos no coinciden, por ejemplo, considere: aaabc,
aab

1
Esto tiene varios errores. CheckSubstring(std::string firstString, std::string secondString)copias profundas de ambas cadenas pasadas a la función, lo cual es costoso, particularmente para cadenas más largas que requieren asignaciones de montón. Además, digamos que llama CheckSubstring("XYZab", "ab\0\0")- el whilebucle terminará comparar aa a, ba b, la NUL implícita al final de la primera cadena a la NUL explícita en la segunda, entonces leerá más allá de amortiguamiento de la primera cadena, que tiene un comportamiento indefinido. Para solucionarlo, use for (... i <= firstString.size () - secondString (). Size (); ...) `.
Tony Delroy

1

Si el tamaño de las cadenas es relativamente grande (cientos de bytes o más) y c ++ 17 está disponible, puede utilizar el buscador Boyer-Moore-Horspool (ejemplo de cppreference.com):

#include <iostream>
#include <string>
#include <algorithm>
#include <functional>

int main()
{
    std::string in = "Lorem ipsum dolor sit amet, consectetur adipiscing elit,"
                     " sed do eiusmod tempor incididunt ut labore et dolore magna aliqua";
    std::string needle = "pisci";
    auto it = std::search(in.begin(), in.end(),
                   std::boyer_moore_searcher(
                       needle.begin(), needle.end()));
    if(it != in.end())
        std::cout << "The string " << needle << " found at offset "
                  << it - in.begin() << '\n';
    else
        std::cout << "The string " << needle << " not found\n";
}

3
Los signos de los tiempos. En los viejos tiempos alguien habría ofrecido una función bool contains(const std::string& haystack, const std::string& needle). Hoy en día, ofrecen un conjunto de piezas de rompecabezas que llevan el nombre de algunos autores oscuros de papeles oscuros para que se parezca más a la informática ...
BitTickler

0

También puede usar el espacio de nombres del sistema. Entonces puedes usar el método contiene.

#include <iostream>
using namespace System;

int main(){
    String ^ wholeString = "My name is Malindu";

    if(wholeString->ToLower()->Contains("malindu")){
        std::cout<<"Found";
    }
    else{
        std::cout<<"Not Found";
    }
}

Esta respuesta solo se aplica a la extensión C ++ propietaria de Microsoft, ya sea C ++ / CX o C ++ / CLI
H. Al-Amri

1
Sí, lo siento, no sabía que solo funciona de esa manera hasta algunos días después de publicarlo.
Malindu Dilanka

-1

Esta es una función simple.

bool find(string line, string sWord)
{
    bool flag = false;
    int index = 0, i, helper = 0;
    for (i = 0; i < line.size(); i++)
    {
        if (sWord.at(index) == line.at(i))
        {
            if (flag == false)
            {
                flag = true;
                helper = i;
            }
            index++;
        }
        else
        {
            flag = false;
            index = 0;
        }
        if (index == sWord.size())
        {
            break;
        }
    }
    if ((i+1-helper) == index)
    {
        return true;
    }
    return false;
}

44
Hola, bienvenido a SO. ¿Podría editar su respuesta y agregar un comentario sobre cómo funciona y cómo se diferencia de otras respuestas? ¡Gracias!
Fabio dice que reinstala a Monica el

-1
#include <algorithm>        // std::search
#include <string>
using std::search; using std::count; using std::string;

int main() {
    string mystring = "The needle in the haystack";
    string str = "needle";
    string::const_iterator it;
    it = search(mystring.begin(), mystring.end(), 
                str.begin(), str.end()) != mystring.end();

    // if string is found... returns iterator to str's first element in mystring
    // if string is not found... returns iterator to mystring.end()

if (it != mystring.end())
    // string is found
else
    // not found

return 0;
}

11
Intente evitar simplemente descargar el código como respuesta e intente explicar qué hace y por qué. Es posible que su código no sea obvio para las personas que no tienen la experiencia de codificación relevante. Edite su respuesta para incluir aclaraciones, contexto e intente mencionar cualquier limitación, suposición o simplificación en su respuesta.
Sᴀᴍ Onᴇᴌᴀ

Gracias por aclarar el código, por usar usingsolo las funciones requeridas y no volcar todo el espacio de nombres en el espacio global. En cuanto al comentario de @ SᴀᴍOnᴇᴌᴀ, supongo que el usuario no leyó los comentarios en su código.
v010dya

-2

De tantas respuestas en este sitio web, no encontré una respuesta clara, así que en 5-10 minutos descubrí la respuesta yo mismo. Pero esto se puede hacer en dos casos:

  1. O SABES la posición de la subcadena que buscas en la cadena
  2. O no conoces la posición y la buscas, char por char ...

Entonces, supongamos que buscamos la subcadena "cd" en la cadena "abcde", y utilizamos la función incorporada de substr más simple en C ++

para 1:

#include <iostream>
#include <string>

    using namespace std;
int i;

int main()
{
    string a = "abcde";
    string b = a.substr(2,2);    // 2 will be c. Why? because we start counting from 0 in a string, not from 1.

    cout << "substring of a is: " << b << endl;
    return 0;
}

para 2:

#include <iostream>
#include <string>

using namespace std;
int i;

int main()
{
    string a = "abcde";

    for (i=0;i<a.length(); i++)
    {
        if (a.substr(i,2) == "cd")
        {
        cout << "substring of a is: " << a.substr(i,2) << endl;    // i will iterate from 0 to 5 and will display the substring only when the condition is fullfilled 
        }
    }
    return 0;
}

2
¿De qué manera la respuesta principal ("use std :: string :: find"), publicada 8 años antes, no es lo suficientemente clara?
Steve Smith el

-3

Podemos usar este método en su lugar. Solo un ejemplo de mis proyectos. Consulte el código. Algunos extras también están incluidos.

¡Mira las declaraciones if!

/*
Every C++ program should have an entry point. Usually, this is the main function.
Every C++ Statement ends with a ';' (semi-colon)
But, pre-processor statements do not have ';'s at end.
Also, every console program can be ended using "cin.get();" statement, so that the console won't exit instantly.
*/

#include <string>
#include <bits/stdc++.h> //Can Use instead of iostream. Also should be included to use the transform function.

using namespace std;
int main(){ //The main function. This runs first in every program.

    string input;

    while(input!="exit"){
        cin>>input;
        transform(input.begin(),input.end(),input.begin(),::tolower); //Converts to lowercase.

        if(input.find("name") != std::string::npos){ //Gets a boolean value regarding the availability of the said text.
            cout<<"My Name is AI \n";
        }

        if(input.find("age") != std::string::npos){
            cout<<"My Age is 2 minutes \n";
        }
    }

}

Lo siento, no vi que alguien haya publicado lo mismo que hice anteriormente.
Malindu Dilanka

1
"Suscribirse a mí en YouTube" puede considerarse spam. Por favor, tenga eso en cuenta en el futuro. Además, lea Cómo responder y cómo no ser un spammer
Zoe
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.