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
是一个可选参数,它定义了搜索的起始位置。默认情况下,pos
为0
,这意味着搜索将从字符串的开头开始,除非您明确指定了其他起始位置。
请注意,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++ 的精彩文章,欢迎查阅!