591

I have a variable of type std::string. I want to check if it contains a certain std::string. How would I do that?

Is there a function that returns true if the string is found, and false if it isn't?

Dev Null
  • 4,046
  • 1
  • 19
  • 40
neuromancer
  • 47,047
  • 74
  • 161
  • 217
  • 6
    Do you mean char* string or the string from the STL ? – anthares Feb 26 '10 at 08:23
  • 1
    It's not a char* string. I had to #include to use it. – neuromancer Feb 26 '10 at 09:37
  • 1
    Some of the solutions are using s2 for the string I want to find. Will it still work if I use something like "this is a string" instead of s2? – neuromancer Feb 26 '10 at 10:38
  • 2
    Yes because there is a string literl constructor for std::string type. –  Feb 26 '10 at 16:15
  • 28
    Someone please make a proposal to add `std::basic_string::contains` to the stdlib. – emlai May 05 '16 at 19:15
  • 1
    @emlai: Such a proposal has since been written ([string contains function](http://open-std.org/JTC1/SC22/WG21/docs/papers/2020/p1679r3.html)), and the member function is now in the C++23 draft. – Stephen Jan 02 '21 at 20:58

13 Answers13

872

Use std::string::find as follows:

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

Note: "found!" will be printed if s2 is a substring of s1, both s1 and s2 are of type std::string.

Guy Avraham
  • 2,830
  • 2
  • 31
  • 43
137

You can try using the find function:

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

if (str.find(str2) != string::npos) {
//.. found.
} 
codaddict
  • 410,890
  • 80
  • 476
  • 515
35

Actually, you can try to use boost library,I think std::string doesn't supply enough method to do all the common string operation.In boost,you can just use the 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;
}
vll
  • 7,507
  • 1
  • 23
  • 42
Geng Jiawen
  • 7,297
  • 2
  • 39
  • 36
  • 43
    "I think std::string doesn't supply enough method to do all the common string operation". But there's a `find` method for exactly the task in question. No need to introduce a library dependency. – stefan Jun 23 '14 at 06:35
  • 9
    @stefan ,you are right,there is a find method,but what about split,replace and many other staff.You can compare std::string to the string api in Java.PS:Also I do think contains is much more elegant than find to check if a string contains another string. – Geng Jiawen Jun 23 '14 at 08:01
  • 1
    Also this is short, and more easy to memory. Cpp 17 has add support for filesystem. I hope Cpp 2x will do something for string too. It's very painful lack basic string method support in modern cpp. – Geng Jiawen May 15 '19 at 03:28
  • 1
    Do you really need the "usings"? When I read this code, I have no idea whether `contains` is `std::contains` or `boost::contains`, which seems like a significant drawback. I guess std::contains doesn't currently exist, but I'm not sure it's reasonable to assume the reader has memorized everything that's in std. And `std::contains` might very well exist in some future version of c++, which would break this program. – Don Hatch Oct 23 '19 at 08:06
23

Starting from C++23 you can use std::string::contains

#include <string>

const auto haystack = std::string("haystack with needles");
const auto needle = std::string("needle");

if (haystack.contains(needle))
{
    // found!
}
Synck
  • 845
  • 10
  • 13
  • 16
    It still amazes me, that we had to get to C++23 before this happened. – Kobski Mar 02 '21 at 09:21
  • if you compile the code snippet from your link to cppreference, you will see that it doesn't compile :) – Ben_LCDB Mar 18 '21 at 23:43
  • The contains function has only been implemented recently (January 2021) in Clang and GCC. In the latest version(s) it compiles: https://godbolt.org/z/PGWj4W – Synck Mar 21 '21 at 10:41
  • GCC 11 and Clang 12 support `std::string::contains()` when invoked in C++23/2b mode. – PFee Apr 28 '21 at 23:54
19

You can try this

string s1 = "Hello";
string s2 = "el";
if(strstr(s1.c_str(),s2.c_str()))
{
   cout << " S1 Contains S2";
}
HappyTran
  • 385
  • 4
  • 9
11

In the event if the functionality is critical to your system, it is actually beneficial to use an old strstr method. The std::search method within algorithm is the slowest possible. My guess would be that it takes a lot of time to create those iterators.

The code that i used to time the whole thing is

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

Here i generate random haystacks and search in them the needle. The haystack count is set, but the length of strings within each haystack is increased from 10 in the beginning to 10240 in the end. Most of the time the program spends actually generating random strings, but that is to be expected.

The output is:

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.
v010dya
  • 4,283
  • 5
  • 24
  • 43
4

If the size of strings is relatively big (hundreds of bytes or more) and c++17 is available, you might want to use Boyer-Moore-Horspool searcher (example from 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";
}
Andris
  • 763
  • 6
  • 13
  • 8
    The signs of the times. In the old days someone would have offered a function ``bool contains(const std::string& haystack, const std::string& needle)``. Nowadays, they offer a set of puzzle pieces named after some obscure authors of obscure papers to make it look more like computer science... – BitTickler Feb 20 '20 at 12:35
3

If you don't want to use standard library functions, below is one solution.

#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;
}
Testing123
  • 327
  • 2
  • 10
  • 6
    You are already using std::string, hence your code already depends on std lib. I rly do not see any reason why to avoid the accepted solution using std::string::find. – b00n12 Mar 29 '18 at 12:22
  • Yeah, that's a good point. Didn't think that when I wrote this. I guess what I thought when I wrote this was maybe how to just avoid using std::find. – Testing123 Mar 30 '18 at 01:01
  • 3
    Just for future visitors: This algorithm isn't actually correct. Because "i" never goes back after a failed substring match, some cases are not matched, for example consider: aaabc, aab – sAm_vdP Oct 22 '18 at 14:16
  • 1
    This has several bugs. `CheckSubstring(std::string firstString, std::string secondString)` deep copies both the strings passed to the function, which is expensive, particularly for longer strings that necessitate heap allocations. Further, say you call `CheckSubstring("XYZab", "ab\0\0")` - the `while` loop will end up comparing `a` to `a`, `b` to `b`, the implicit NUL at the end of the first string to the explicit NUL in the second, then it will read beyond the first string's buffer, having undefined behaviour. To fix use `for (... `i <= firstString.size() - secondString().size(); ...)`. – Tony Delroy May 09 '19 at 07:09
2
#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;
}
zaonline
  • 57
  • 1
  • 12
    Please try to avoid just dumping code as an answer and try to explain what it does and why. Your code might not be obvious for people who do not have the relevant coding experience. Please edit your answer to include [clarification, context and try to mention any limitations, assumptions or simplifications in your answer.](https://stackoverflow.com/help/how-to-answer) – Sᴀᴍ Onᴇᴌᴀ Aug 21 '17 at 00:01
  • Thanks for making code clear, for using `using` with only required functions and not dumping entire namespace into the global space. As for @SᴀᴍOnᴇᴌᴀ comment, i guess that user didn't read the comments in your code. – v010dya Nov 14 '19 at 06:53
1

From so many answers in this website I didn't find out a clear answer so in 5-10 minutes I figured it out the answer myself. But this can be done in two cases:

  1. Either you KNOW the position of the sub-string you search for in the string
  2. Either you don't know the position and search for it, char by char...

So, let's assume we search for the substring "cd" in the string "abcde", and we use the simplest substr built-in function in C++

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

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

You can also use the System namespace. Then you can use the contains method.

#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";
    }
}
0

This is a simple function

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;
}
neda
  • 25
  • 1
-2

We can use this method instead. Just an example from my projects. Refer the code. Some extras are also included.

Look to the if statements!

/*
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";
        }
    }

}
Matthew
  • 1,779
  • 3
  • 15
  • 23
  • I'm sorry, I did not see that somebody has posted the same thing I did previously. – Malindu Dilanka Jun 08 '19 at 15:07
  • 1
    "Subscribe to me on YouTube" can be considered spam. Please keep that in mind in the future. Also, read [answer] and [how not to be a spammer](/help/promotion) – Zoe Jun 08 '19 at 16:23