729

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,731
  • 1
  • 30
  • 46
neuromancer
  • 53,769
  • 78
  • 166
  • 223
  • 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
  • 48
    Someone please make a proposal to add `std::basic_string::contains` to the stdlib. – Emil Laine May 05 '16 at 19:15
  • 10
    @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
  • 7
    @Stephen This should have been a thing right from the start. It's mind-boggling that nobody has implemented this until now. – SimonC Dec 01 '21 at 16:08

16 Answers16

1099

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
  • 3,482
  • 3
  • 38
  • 50
  • 2
    What std::string::find returns when trying to find a substring? – maDeveloper Jan 21 '21 at 08:06
  • 2
    It returns the index of the first occurrence of the substring in the string from given starting position. The default value of starting position is 0. – Morris Bahrami Feb 16 '21 at 00:15
  • 2
    per C++ docs std::string::npos is -1. If there is no match then find function returns -1. If there is match then it returns index of the occurrence which is always a positive number. That is why here we are doing != -1 check – Sam B Dec 07 '22 at 17:43
  • @SamB almost correctly! ;) More precise is "0 or a positive number". – Claudiu Cruceanu Feb 28 '23 at 19:16
165

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
  • 445,704
  • 82
  • 492
  • 529
  • Since there is no possible way to Edit the Answer Above (Edit Queue Pending). I'm Leaving more Info regarding the Logic of this Answer (On the Following Link): https://www.cplusplus.com/reference/string/string/npos/ Taking into Consideration the Information found on the website: You Read the If Statement as: "if str2 value not equal to: "not found" (when searching); then the String was Found!" –  Sep 27 '21 at 14:12
90

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
  • 2,727
  • 22
  • 20
  • 151
    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 :) –  Mar 18 '21 at 23:43
  • 1
    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
  • 1
    GCC 11 and Clang 12 support `std::string::contains()` when invoked in C++23/2b mode. – PFee Apr 28 '21 at 23:54
  • @Kobski well, yes. But it is not as useful as it looks. It returns a bool. If you want to do something with the original (long) string you have to search again in some other way. It doesn’t even tell you if it is contained more than once, where, etc. – alfC Sep 14 '21 at 23:24
  • 8
    @alfC It is exactly as useful as it looks - it tells you whether a string contains a certain substring/character or not. often that is all you need. if you care about its position then you would use `find` to tell you its location. – ABaumstumpf Mar 07 '22 at 12:13
  • 2
    To understand why it exists have a look [here](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1679r0.html#:~:text=A%20contains%20member%20function%20would,the%20intention%20of%20the%20programmer.) – Angaj Sharma Aug 22 '22 at 09:12
  • what's the time complexity of this function ? – Than Win Hline Jan 26 '23 at 18:27
  • same complexity as `find` (which is used under the hood) – Synck Feb 06 '23 at 13:12
41

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
  • 9,634
  • 1
  • 29
  • 54
Geng Jiawen
  • 8,904
  • 3
  • 48
  • 37
  • 48
    "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
  • 2
    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
30

You can try this

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

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
  • 5,296
  • 7
  • 28
  • 48
7

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
  • 921
  • 7
  • 14
  • 25
    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
5

what about

string response = "hello world";
string findMe = "world";

if(response.find(findMe) != string::npos)
{
     //found
}
jerryurenaa
  • 3,863
  • 1
  • 27
  • 17
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
  • 363
  • 2
  • 12
  • 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
3

Good to use std::regex_search also. Stepping stone for making the search more generic. Below is an example with comments.

//THE STRING IN WHICH THE SUBSTRING TO BE FOUND.
std::string testString = "Find Something In This Test String";

//THE SUBSTRING TO BE FOUND.
auto pattern{ "In This Test" };

//std::regex_constants::icase - TO IGNORE CASE.
auto rx = std::regex{ pattern,std::regex_constants::icase };

//SEARCH THE STRING.
bool isStrExists = std::regex_search(testString, rx);

Need to include #include <regex>

For some reason, suppose the input string is observed something like "Find Something In This Example String", and interested to search either "In This Test" or "In This Example" then the search can be enhanced by simply adjusting the pattern as shown below.

//THE SUBSTRING TO BE FOUND.
auto pattern{ "In This (Test|Example)" };
Pavan Chandaka
  • 11,671
  • 5
  • 26
  • 34
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
  • 14
    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;
}
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
0

Note: I know that the question requires a function, which means the user is trying to find something simpler. But still I post it in case anyone finds it useful.

Approach using a Suffix Automaton. It accepts a string (haystack), and after that you can input hundreds of thousands of queries (needles) and the response will be very fast, even if the haystack and/or needles are very long strings.

Read about the data structure being used here: https://en.wikipedia.org/wiki/Suffix_automaton

#include <bits/stdc++.h>

using namespace std;

struct State {
  int len, link;
  map<char, int> next;
};

struct SuffixAutomaton {
  vector<State> st;
  int sz = 1, last = 0;

  SuffixAutomaton(string& s) {
    st.assign(s.size() * 2, State());
    st[0].len = 0;
    st[0].link = -1;
    for (char c : s) extend(c);
  }

  void extend(char c) {
    int cur = sz++, p = last;
    st[cur].len = st[last].len + 1;
    while (p != -1 && !st[p].next.count(c)) st[p].next[c] = cur, p = st[p].link;
    if (p == -1)
      st[cur].link = 0;
    else {
      int q = st[p].next[c];
      if (st[p].len + 1 == st[q].len)
        st[cur].link = q;
      else {
        int clone = sz++;
        st[clone].len = st[p].len + 1;
        st[clone].next = st[q].next;
        st[clone].link = st[q].link;
        while (p != -1 && st[p].next[c] == q) st[p].next[c] = clone, p = st[p].link;

        st[q].link = st[cur].link = clone;
      }
    }
    last = cur;
  }
};

bool is_substring(SuffixAutomaton& sa, string& query) {
  int curr = 0;

  for (char c : query)
    if (sa.st[curr].next.count(c))
      curr = sa.st[curr].next[c];
    else
      return false;

  return true;
}

// How to use:
// Execute the code
// Type the first string so the program reads it. This will be the string
// to search substrings on.
// After that, type a substring. When pressing enter you'll get the message showing the
// result. Continue typing substrings.
int main() {
  string S;
  cin >> S;

  SuffixAutomaton sa(S);

  string query;
  while (cin >> query) {
    cout << "is substring? -> " << is_substring(sa, query) << endl;
  }
}

Chris Vilches
  • 986
  • 2
  • 10
  • 25
-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";
    }
}
-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,905
  • 3
  • 19
  • 26
  • 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