C++字符串查找:深入解析find()方法与实用技巧

本文将深入探讨如何在C++中使用字符串的find()函数。

当我们需要检查一个字符串是否包含另一个子字符串时,std::string::find()方法是一个非常有用的工具。接下来,我们将通过一些实例来详细了解它的用法!


C++中字符串find()的语法

find()方法是C++标准库中std::string类的一个成员函数。因此,在使用它之前,我们必须包含相应的头文件(通常是<string>)。

我们必须在一个std::string对象上调用此函数,并传入另一个字符串作为参数。find()方法会检查给定的子字符串是否存在于我们的主字符串中。如果找到,它将返回子字符串首次出现的位置(索引),类型为size_t。如果子字符串不存在,它将返回std::string::npos(一个表示“未找到”的特殊值,通常是size_t的最大值)。

以下是find()函数的一种常见定义形式:

size_t find(const std::string& my_string, size_t pos = 0);

其中,pos是一个可选参数,它定义了搜索的起始位置。默认情况下,pos0,这意味着搜索将从字符串的开头开始,除非您明确指定了其他起始位置。

请注意,my_string参数是以常量引用(const std::string&)的方式传递的。由于我们不会修改传入的字符串,使用引用可以避免不必要的字符串复制,从而提高效率。

注意: 从C++20开始,许多标准库方法现在支持constexpr,这意味着它们可以在编译时执行。您可以查阅更多关于constexpr的复杂性。

find()函数有多个重载版本,其中大部分我们在此将不详细展开,您可以在cppreference.com上查看更多信息。相反,我们将重点关注一个涉及子字符串长度的特定重载:

size_t find( const Char* s, size_type pos, size_type count )

这个特定的重载用于检查子字符串是否位于我们的字符串中,但它还对子字符串的长度有限制。它会匹配直到指定的字符数(由count参数决定)。

需要注意的是,这个重载不能直接用于std::string对象。请留意原型中的const Char*,这表明它只能用于C风格的字符串(即字符数组或字符串字面量)。

例如,如果我们将子字符串“Hell”传递给这个函数,并限制匹配长度为3:

std::cout << "Hello".find("Hell", 0, 3) << std::endl;

这只会匹配“Hello”中的前3个字符(即“Hel”)。因此,作为输出,它将返回0(因为“Hel”在“Hello”的索引0处)。

现在,让我们通过一些具体的例子来巩固我们所学的知识。


在C++中使用string.find()函数

这是文章《如何在C++中使用字符串的find()方法》的第2部分(共3部分)。

让我们来看一下find()方法的默认调用,即当pos=0时。在这种情况下,我们将简单地从字符串的开头开始搜索整个子字符串。

#include <iostream>
#include <string>

int main() {
    // 创建我们的字符串
    std::string my_str("Hello from JournalDev");
    // 目标搜索字符串
    std::string target_string("JournalDev");

    std::cout << "'" << target_string << "' 是不是 '" << my_str << "' 的子字符串?\n";
    size_t substring_length = my_str.find(target_string);
    if (substring_length == 0)
        std::cout << "否\n";
    else
        std::cout << "匹配子字符串的起始索引 = " << substring_length << std::endl;

    return 0;
}

输出:

'JournalDev' 是不是 'Hello from JournalDev' 的子字符串?
匹配子字符串的起始索引 = 11

你可以看到,在我们的原始字符串中确实存在这个子字符串!find()方法返回了子字符串在主字符串中的起始索引。

现在,让我们尝试从字符串的特定位置开始搜索相同的子字符串。

#include <iostream>
#include <string>

int main() {
    // 创建我们的字符串
    std::string my_str("Hello from JournalDev");
    // 目标搜索字符串
    std::string target_string("JournalDev");

    std::cout << "'" << target_string << "' 是不是 '" << my_str << "' 的子字符串?\n";
    size_t substring_length = my_str.find(target_string, 12); // 从索引12开始搜索 (my_str[12]处)
    if (substring_length == 0)
        std::cout << "否\n";
    else
        std::cout << "匹配子字符串的起始索引 = " << substring_length << std::endl;

    return 0;
}

输出:

'JournalDev' 是不是 'Hello from JournalDev' 的子字符串?
匹配子字符串的起始索引 = 18446744073709551615

为什么我们得到了这样奇怪的输出?因为我们从原始字符串的第12个索引开始搜索,而目标子字符串"JournalDev"的实际起始索引是11。从索引12开始,字符串的剩余部分不足以包含完整的"JournalDev"。在这种情况下,find()方法会返回一个特殊值,表示未找到匹配项。这个特殊值通常是std::string::npos,它是一个非常大的无符号整数值,在某些系统上可能显示为18446744073709551615

因此,当find()方法未能找到匹配项时,它会返回std::string::npos。我们需要通过检查返回值是否等于std::string::npos来判断是否找到了子字符串。

C++中有一个特殊的常量叫做std::string::npos,它表示“未找到”或“字符串的末尾”。我们可以用它来检测find()方法是否找到了匹配项。

if (my_str.find(target_str) != std::string::npos) {
    // 找到了匹配项!我们仍在原始字符串范围内
}
else {
    // 糟糕!未找到匹配项。打印错误信息!
}

有了这个改进,我们的代码现在将变成这样:

#include <iostream>
#include <string>

int main() {
    // 创建我们的字符串
    std::string my_str("Hello from JournalDev");
    // 目标搜索字符串
    std::string target_string("JournalDev");

    std::cout << "'" << target_string << "' 是不是 '" << my_str << "' 的子字符串?\n";
    size_t substring_length;
    if ((substring_length = my_str.find(target_string, 12)) != std::string::npos) {
        std::cout << "匹配子字符串的起始索引 = " << substring_length << std::endl;
    }
    else {
        std::cout << "否\n";
    }

    return 0;
}

输出:

'JournalDev' 是不是 'Hello from JournalDev' 的子字符串?
否

现在,我们得到了我们期望的输出,因为我们从索引12开始搜索,而从该位置开始无法找到完整的“JournalDev”子字符串。

让我们使用这个检查来展示find()的另一种重载形式,它接受一个计数参数。请记住,我们不能直接对std::string对象使用这种形式,它通常用于C风格的字符串(const char*)。

#include <iostream>
#include <string>

int main() {
    // 创建我们的字符串
    std::string my_str("Hello from JournalDev");
    // 目标搜索字符串
    std::string target_string("Journ_kkfffsfsfskkk");

    std::cout << "'" << target_string << "' 是不是 '" << my_str << "' 的子字符串?\n";
    size_t substring_length;
    // 使用计数参数,只匹配前5个字符
    // 注意:这种形式通常用于 const char* 字符串
    if ((substring_length = my_str.find("Journ_kkfffsfsfskkk", 0, 5)) != std::string::npos) {
        std::cout << "匹配子字符串的起始索引 = " << substring_length << std::endl;
    }
    else {
        std::cout << "否\n";
    }

    return 0;
}

输出:

'Journ_kkfffsfsfskkk' 是不是 'Hello from JournalDev' 的子字符串?
匹配子字符串的起始索引 = 11

请注意,我们已经改变了目标字符串。尽管target_string很长,但由于我们设置了计数限制为5,find()方法只会尝试匹配"Journ"这前5个字符。对于find()来说,这已经足够了!

因此,它会忽略目标子字符串的其余部分,并继续在原始字符串中进行匹配,直到找到符合条件的子序列。这就是为什么我们仍然得到11作为起始索引,因为它是找到“Journ”子字符串匹配的位置。


结论

希望通过这些示例,您已经清楚地了解了如何在 C++ 中轻松使用 string.find() 方法。如果您有任何疑问,请在下方的评论区提出!

此外,在我们的教程部分还有其他关于 C++ 的精彩文章,欢迎查阅!


参考文献


bannerAds