题目

编写程序,在给定的长文本中查找指定子串出现的所有位置索引,并截取包含上下文的关键片段。重点掌握 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..."