ChatGPT解决这个技术问题 Extra ChatGPT

检查字符串是否包含 C++ 中的字符串

我有一个 std::string 类型的变量。我想检查它是否包含某个std::string。我该怎么做?

如果找到字符串,是否有一个函数返回true,如果没有,则返回false?

你的意思是 char* 字符串还是来自 STL 的字符串?
它不是 char* 字符串。我必须 #include 才能使用它。
是的,因为 std::string 类型有一个字符串 literl 构造函数。
请有人提议将 std::basic_string::contains 添加到标准库。
@emlai:已经编写了这样的提案(string contains function),并且成员函数现在在 C++23 草案中。

G
Guy Avraham

按如下方式使用 std::string::find

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

注:“找到了!”如果 s2s1 的子字符串,则将打印,s1s2 都是 std::string 类型。


尝试查找子字符串时 std::string::find 返回什么?
它从给定的起始位置返回字符串中第一次出现的子字符串的索引。起始位置的默认值为 0。
c
codaddict

您可以尝试使用 find 函数:

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

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

由于无法编辑上面的答案(编辑队列挂起)。我将留下有关此答案逻辑的更多信息(在以下链接上):cplusplus.com/reference/string/string/npos 考虑到网站上找到的信息:您将 If 语句阅读为:“如果 str2 值不等于:”未找到“(搜索时);然后找到字符串!”
S
Synck

从 C++23 开始,您可以使用 std::string::contains

#include <string>

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

if (haystack.contains(needle))
{
    // found!
}

仍然让我感到惊讶的是,我们必须在这发生之前到达 C++23。
如果您从指向 cppreference 的链接中编译代码片段,您将看到它无法编译:)
contains 函数最近(2021 年 1 月)才在 Clang 和 GCC 中实现。在最新版本中,它编译:godbolt.org/z/PGWj4W
GCC 11 和 Clang 12 在 C++23/2b 模式下调用时支持 std::string::contains()
@alfC 它和它看起来一样有用——它告诉你一个字符串是否包含某个子字符串/字符。通常这就是你所需要的。如果您关心它的位置,那么您将使用 find 告诉您它的位置。
V
VLL

实际上,您可以尝试使用 boost 库,我认为 std::string 没有提供足够的方法来执行所有常见的字符串操作。在 boost 中,您可以只使用 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;
}

“我认为 std::string 没有提供足够的方法来执行所有常见的字符串操作”。但是有一个 find 方法可以解决所讨论的任务。无需引入库依赖项。
@stefan,你是对的,有一个 find 方法,但是 split、replace 和许多其他人员呢。您可以将 std::string 与 Java 中的字符串 api 进行比较。PS:我也认为 contains 比包含更优雅find 检查一个字符串是否包含另一个字符串。
这也很短,更容易记忆。 Cpp 17 增加了对文件系统的支持。我希望 Cpp 2x 也能为字符串做点什么。在现代 cpp 中缺乏基本的字符串方法支持是非常痛苦的。
你真的需要“使用”吗?当我阅读这段代码时,我不知道 containsstd::contains 还是 boost::contains,这似乎是一个很大的缺点。我猜 std::contains 目前不存在,但我不确定假设读者已经记住了 std 中的所有内容是否合理。并且 std::contains 很可能存在于某些未来版本的 c++ 中,这会破坏该程序。
H
HappyTran

你可以试试这个

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

不适用于包含 NUL 字符的字符串。
v
v010dya

如果该功能对您的系统至关重要,那么使用旧的 strstr 方法实际上是有益的。 algorithm 中的 std::search 方法可能是最慢的。我的猜测是创建这些迭代器需要很多时间。

我用来计时整个事情的代码是

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

在这里,我生成随机 haystacks 并在其中搜索 needle。 haystack 计数已设置,但每个 haystack 中的字符串长度从开始的 10 增加到最后的 10240。大多数时候,程序实际上花费在生成随机字符串上,但这是意料之中的。

输出是:

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.

答案的简短版本是:使用 c 而不是 c++ :)
A
Andris

如果字符串的大小相对较大(数百字节或更多)并且 c++17 可用,您可能需要使用 Boyer-Moore-Horspool 搜索器(来自 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";
}

时代的痕迹。在过去,有人会提供函数 bool contains(const std::string& haystack, const std::string& needle)。如今,他们提供了一组以一些默默无闻的论文作者命名的拼图,使其看起来更像计算机科学......
T
Testing123

如果您不想使用标准库函数,以下是一种解决方案。

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

您已经在使用 std::string,因此您的代码已经依赖于 std lib。我看不出有任何理由避免使用 std::string::find 来接受已接受的解决方案。
是的,这是一个很好的观点。写这篇的时候没想到。我想我写这篇文章时的想法可能是如何避免使用 std::find。
仅供未来访问者使用:此算法实际上并不正确。因为“i”在子字符串匹配失败后从不返回,所以有些情况不匹配,例如考虑:aaabc、aab
这有几个错误。 CheckSubstring(std::string firstString, std::string secondString) 深度复制传递给函数的两个字符串,这很昂贵,特别是对于需要堆分配的较长字符串。此外,假设您调用 CheckSubstring("XYZab", "ab\0\0") - while 循环最终会将 aabb 进行比较,即第一个字符串末尾的隐式 NUL 与其次,它将读取超出第一个字符串的缓冲区,具有未定义的行为。要修复使用 for (... i <= firstString.size() - secondString().size(); ...)`。
z
zaonline
#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;
}

请尽量避免仅仅将代码作为答案,并尝试解释它的作用和原因。对于没有相关编码经验的人来说,您的代码可能并不明显。请编辑您的答案以包括 clarification, context and try to mention any limitations, assumptions or simplifications in your answer.
感谢您使代码清晰,将 using 与仅必需的函数一起使用,而不是将整个命名空间转储到全局空间中。至于@SᴀᴍOnᴇᴌᴀ 评论,我猜该用户没有阅读您代码中的评论。
P
Pavan Chandaka

也很适合使用 std::regex_search。使搜索更通用的垫脚石。下面是一个带有注释的示例。

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

需要包含#include <regex>

出于某种原因,假设观察到输入字符串类似于“在此示例字符串中查找内容”,并且有兴趣搜索“在此测试中”或“在此示例中”,则可以通过简单地调整模式来增强搜索,如图所示以下。

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

u
user7655194

从这个网站上的这么多答案中,我没有找到一个明确的答案,所以在 5-10 分钟内我自己想出了答案。但这可以在两种情况下完成:

要么你知道你在字符串中搜索的子字符串的位置要么你不知道位置并搜索它,逐个字符......

因此,假设我们在字符串“abcde”中搜索子字符串“cd”,并且我们使用 C++ 中最简单的 substr 内置函数

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

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

年前发布的最佳答案(“使用 std::string::find”)以何种方式不够清楚?
n
neda

这是一个简单的功能

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

您好,欢迎来到 SO。您能否edit您的答案并添加评论,说明它的工作原理以及它与其他答案的不同之处?谢谢!
M
Malindu Dilanka

您还可以使用 System 命名空间。然后你可以使用 contains 方法。

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

此答案仅适用于 Microsoft 的专有 C++ 扩展 C++/CX 或 C++/CLI
是的,我很抱歉,直到我发布它的几天后,我才知道它只能这样工作。
C
Chris Vilches

注意:我知道这个问题需要一个函数,这意味着用户正在尝试找到更简单的东西。但我仍然发布它以防有人发现它有用。

使用后缀自动机的方法。它接受一个字符串(haystack),然后您可以输入数十万个查询(needles)并且响应将非常快,即使 haystack 和/或 needle 是非常长的字符串。

阅读此处使用的数据结构: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;
  }
}


M
Matthew

我们可以改用这种方法。只是我项目中的一个例子。参考代码。一些额外的东西也包括在内。

查看 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";
        }
    }

}

对不起,我没有看到有人发布了与我之前所做的相同的事情。
“在 YouTube 上订阅我”可被视为垃圾邮件。今后请牢记这一点。另外,请阅读 How to Answerhow not to be a spammer