用std::string::find循环查找最直接,正确做法是pos = str.find(sub, pos + sub.length())避免重叠匹配;复杂模式用std::regex_iterator;单字符统计用std::count最高效;只读场景优先用std::string_view提升性能。

用 std::string::find 循环查找最直接
不需要额外依赖,std::string 自带的 find 就能完成子串计数。关键在于每次找到后把搜索起始位置移到匹配结束之后,避免重叠或死循环。
常见错误是写成 pos = str.find(sub, pos + 1)——这会跳过长度 > 1 的子串的重叠匹配(比如在 "aaaa" 中找 "aa",该写法只返回 2 次,而实际可匹配 3 次)。正确做法是 pos = str.find(sub, pos + sub.length())。
- 如果要统计非重叠出现(默认语义),用
pos + sub.length() - 如果要统计所有可能重叠位置(如算法题要求),用
pos + 1 - 记得检查
find返回值是否为std::string::npos,否则会无限循环
size_t count = 0;
size_t pos = 0;
while ((pos = str.find(sub, pos)) != std::string::npos) {
++count;
pos += sub.length(); // 非重叠;若需重叠,改为 pos += 1
}
用 std::regex_iterator 处理复杂模式
当要统计的是“符合某种规则”的字符串片段(比如所有数字序列、邮箱格式、带大小写不敏感的关键词),正则比手动 find 更可靠。
注意:C++11 起支持 <regex>,但部分旧编译器(如 GCC 4.9 前)实现不完整;MSVC 和较新 Clang 通常没问题。性能上,正则初始化开销大,单次查找不如 find 快,但模式复用时更清晰。
立即学习“C++免费学习笔记(深入)”;
- 构造
std::regex时传入std::regex_constants::icase可忽略大小写 - 用
std::sregex_iterator遍历时,迭代器解引用得到std::smatch,.str()取匹配内容 - 空匹配(如
regex(""))会导致无限迭代,务必避免
std::regex re("ab+", std::regex_constants::icase);
auto begin = std::sregex_iterator(str.begin(), str.end(), re);
auto end = std::sregex_iterator();
size_t count = std::distance(begin, end);
统计单字符出现次数用 std::count 最高效
如果是统计某个字符(如 'a' 或 '\n')在字符串里出现多少次,别手写循环或调 find——<algorithm> 里的 std::count 是专为此优化的,底层常展开为 SIMD 指令。
它接受任意迭代器范围,所以也能用于 std::vector<char> 或 C 风格字符串(配合 begin()/end() 或 std::strlen)。
- 参数顺序是
std::count(first, last, value),不是(value, first, last) - 对
std::string直接传s.begin(), s.end(), 'x'即可 - 不要误用
std::count_if去判断单字符——多一层函数调用,无必要
size_t count = std::count(str.begin(), str.end(), 'e');
注意 std::string_view 在 C++17+ 中的零拷贝优势
如果你的字符串源是只读的(比如配置文本、日志行),且统计逻辑在函数内部,用 std::string_view 替代 const std::string& 参数能避免隐式构造和内存分配。
所有上面提到的方法(find、std::count、std::regex_iterator)都支持 string_view,只需确保正则构造时用 sv.data() 和 sv.size() 显式传递底层数据——不过多数情况下直接传 string_view 给 regex_iterator 构造函数也 OK。
- 传参时优先用
std::string_view,尤其函数被高频调用时 -
string_view的find行为和string完全一致,无需改逻辑 - 切记:
string_view不拥有数据,确保其引用的原始字符串生命周期长于统计过程
重叠匹配、正则边界、string_view 生命周期——这三个点,实际写业务代码时最容易漏掉。


















