std::string::find需循环调用以查找全部匹配位置,每次找到后pos++实现重叠匹配(如"aaaa"中找"aa"得[0,1,2]),非重叠则pos+=sub.length();须预检空串防死循环,注意size_t与int类型安全及npos比较陷阱。

用 std::string::find 循环查找最直接
标准库没提供“找全部索引”的一键函数,std::string::find 是唯一可靠起点。它返回首次匹配位置,失败时返回 std::string::npos,必须用循环推进起始位置。
关键点是每次找到后,下次搜索从 pos + 1 开始(不是 pos + sub.length()),否则会漏掉重叠匹配,比如在 "aaaa" 中找 "aa",正确结果应是 [0, 1, 2]。
std::vector<size_t> findAll(const std::string& s, const std::string& sub) {
std::vector<size_t> indices;
size_t pos = 0;
while ((pos = s.find(sub, pos)) != std::string::npos) {
indices.push_back(pos);
pos++; // 注意:不是 pos += sub.length()
}
return indices;
}
重叠匹配 vs 非重叠匹配要手动控制
是否允许重叠,取决于业务逻辑,C++ 标准库不区分这两种模式,全靠你控制 pos 的递增值。
- 要非重叠(跳过已匹配字符):用
pos += sub.length() - 要重叠(每个位置都试):用
pos++ - 如果
sub为空字符串,find永远返回当前pos,必须提前检查,否则死循环
性能敏感时别用 find 反复扫描
对超长字符串(比如百MB文本)和高频调用场景,find 的朴素实现会退化成 O(n×m),实际可能卡顿。
立即学习“C++免费学习笔记(深入)”;
可选替代方案:
- 用
std::boyer_moore_searcher(C++17 起),需构造std::string_view和 searcher,初始化开销略大但搜索快 - 自己实现 KMP,适合固定子串重复搜索;注意
std::string内部不保证连续内存(C++11 后基本保证,但别依赖) - 若子串极短(如单字符),直接用
std::find配合迭代器更轻量
注意 size_t 溢出和符号转换问题
std::string::npos 是 size_t 最大值(通常是 0xFFFFFFFFFFFFFFFF),和 -1 不等价。写成 if (pos == -1) 会隐式转换出错,永远为 false。
常见错误写法:
-
for (int i = 0; (i = s.find(sub, i)) != -1; i++)——i是int,但find返回size_t,比较前会被提升为无符号,-1 变成极大正数 - 把
size_t存进int或long容器,遇到超长字符串(索引 > 2³¹)就截断
安全做法:统一用 size_t 类型,或用 auto 让编译器推导。
pos 怎么更新、类型怎么选、空串怎么处理,这几个地方一错就得不到预期结果。


















