题目
编写程序,在给定的长文本中查找指定子串出现的所有位置索引,并截取包含上下文的关键片段。重点掌握 std::string::npos 的常量含义(无符号最大值 size_t(-1)),演示若错误地用有符号 int 接收查找返回值会导致的比较逻辑错误及 substr 下标越界防御。
输入格式:第一行输入待检索的源文本;第二行输入待检索的子串关键字。
输出格式:依次输出所有命中索引位置;若未找到输出明确安全提示。
数据范围与约定:字符串长度 <code>≤ 10^5</code>。
思路与算法
1. npos 的本质std::string::npos 是 static const size_t 类型的静态成员,数值通常为 18446744073709551615(64 位系统下)。切勿用 int pos 接收 str.find(),在某些架构下发生符号截断可能导致 pos == -1 意外成立或死循环。
2. 游标步进查找算法
从位置 0 开始调用 str.find(target, currentPos),一旦命中记录下标并将下次起始位置更新为 pos + target.size(),循环直到返回 std::string::npos。
3. substr 边界安全性
调用 str.substr(pos, count) 时,若 pos > str.size() 会抛出 std::out_of_range 异常;但如果 pos 合法而 pos + count > str.size(),标准规定会自动安全截取到字符串末尾而不会崩溃。
完整程序
#include <iostream>
#include <string>
#include <vector>
int main() {
std::string text, pattern;
if (!std::getline(std::cin, text) || !std::getline(std::cin, pattern)) {
return 0;
}
if (pattern.empty()) {
std::cout << "错误:检索模式串不能为空。\n";
return 1;
}
std::vector<std::string::size_type> matches;
std::string::size_type pos = 0;
// 游标迭代查找所有命中位置
while ((pos = text.find(pattern, pos)) != std::string::npos) {
matches.push_back(pos);
pos += pattern.length(); // 步进避开当前匹配项
}
if (matches.empty()) {
std::cout << "未在文本中检索到子串: \"" << pattern << "\"\n";
} else {
std::cout << "成功命中 " << matches.size() << " 处,匹配起始位置分别为: ";
for (std::string::size_type idx : matches) {
std::cout << idx << " ";
}
std::cout << "\n";
// 输出首个命中的局部上下文(安全截取前5后5字符)
std::string::size_type first = matches.front();
std::string::size_type start = (first >= 5) ? (first - 5) : 0;
std::string::size_type len = (first - start) + pattern.length() + 5;
std::cout << "首个命中上下文片段: \"..." << text.substr(start, len) << "...\"\n";
}
return 0;
}运行示例
输入:
The quick brown fox jumps over the lazy dog. Fox is agile.
fox输出:
成功命中 1 处,匹配起始位置分别为: 16
首个命中上下文片段: "...rown fox jump..."