C++ 字符串截取

从一个完整的字符串里提取出某一部分内容,通常称为 “字符串截取”,比如从网址 "www.lvyenet.com" 中取出域名,或者从日期 "2026-10-20" 中取出月份。

在 C++ 中,我们可以使用 std::string 提供的 substr() 成员函数来实现。其中,substr 是 “substring(子字符串)” 的缩写。

截取指定长度的子串

调用 substr() 函数时,最常用的方式是传入 2 个参数,分别指定 “从哪个下标开始截” 以及 “一共截取多少个字符”。

语法:

str.substr(pos, count)

说明:

调用 substr(pos, count) 会返回一个新生成的子字符串,它的 2 个参数含义如下:

  • pos(必选):是 “position(位置)” 的缩写,表示从哪个下标位置开始截取,下标从 0 开始计算。
  • count(可选):表示从 pos 位置开始,向后连续截取的字符个数。需要注意,这里是 “字符数量”,而不是结束下标。

我们先来看一下字符串 "lvyenet" 中每个字符对应的下标位置,如下表所示。

字符与下标位置
字符位置 下标 对应字符
第 1 个字符 0 'l'
第 2 个字符 1 'v'
第 3 个字符 2 'y'
第 4 个字符 3 'e'
第 5 个字符 4 'n'
第 6 个字符 5 'e'
第 7 个字符 6 't'

如果我们想从中取出前面的 "lvye",只需要从下标 0 开始取 4 个字符;如果想取出后面的 "net",只需要从下标 4 开始取 3 个字符。

示例 1:截取指定长度的子串

#include <iostream>
#include <string>

int main() {
    std::string text = "lvyenet";

    std::string first = text.substr(0, 4);
    std::string second = text.substr(4, 3);

    std::cout << first << '\n';
    std::cout << second << '\n';
    std::cout << text << '\n';
    return 0;
}

运行结果如下。

lvye
net
lvyenet

分析:

在上面例子中,text.substr(0, 4) 从下标 0 处的 'l' 开始连续取出 4 个字符,得到 "lvye"。text.substr(4, 3) 则从下标 4 处的 'n' 开始取出 3 个字符,得到 "net"。

很多接触过 Python 或 JavaScript 的小伙伴,容易把 substr(pos, count) 的第 2 个参数误当成 “结束下标”。比如想从日期 "2026-10-20" 中提取月份 "10",我们可以对比下面两种写法:

std::string date = "2026-10-20";

// 正确方式
std::string month1 = date.substr(5, 2);

// 错误方式
std::string month2 = date.substr(5, 7);

上面代码中,月份 "10" 从下标 5 开始,一共只有 2 个字符,因此第 2 个参数应该传入 2。如果误把结束下标 7 传进去,程序就会从下标 5 开始往后截取 7 个字符,结果就变成了 "10-20"。

下面代码中,sub 的最终值是 "gram",小伙伴们可以对照下标算一算为什么。

std::string word = "program";
std::string sub = word.substr(3, 4);

注意 调用 substr() 不会修改原字符串本身,而是返回一个新字符串。如果希望更新原变量的内容,记得写成 text = text.substr(0, 4); 重新接收返回值。

截取到字符串末尾

很多时候,我们只知道要从哪个下标位置开始截,并且希望把后面的内容一直截取到字符串末尾,却不想自己去算后面还剩多少个字符。

遇到这种情况,我们可以直接省略第 2 个参数 count,只传入起始位置 pos 即可。

语法:

str.substr(pos)

说明:

当省略第 2 个参数时,substr(pos) 默认会从下标 pos 开始,把后面剩余的所有字符一直截取到字符串末尾。

示例 2:截取到字符串末尾

#include <iostream>
#include <string>

int main() {
    std::string url = "www.lvyenet.com";
    std::string domain = url.substr(4);

    std::cout << domain << '\n';
    return 0;
}

运行结果如下。

lvyenet.com

分析:

在 "www.lvyenet.com" 中,开头的 "www." 占了 4 个字符,字母 'l' 的下标正好是 4。

调用 url.substr(4) 会从下标 4 一路截取到末尾,直接得到 "lvyenet.com",省去了手动调用 size() 计算剩余长度的步骤。

C++ substr() 注意事项

在使用 substr(pos, count) 时,如果传进去的数字超过了字符串的长度,会发生什么情况呢?实际上,第 2 个参数 count 超出范围,与第 1 个参数 pos 超出范围,两者的表现完全不一样。

1. 截取个数 count 超出剩余长度

如果第 2 个参数 count 超过了从 pos 开始往后剩下的字符总数,substr() 并不会报错,而是截取到字符串末尾就自动停下来。如果把 count 写成 0,则会返回一个空字符串 ""。

示例 3:count 超过剩余长度

#include <iostream>
#include <string>

int main() {
    std::string text = "Hello";

    std::string sub1 = text.substr(2, 100);
    std::string sub2 = text.substr(2, 0);

    std::cout << "[" << sub1 << "]" << '\n';
    std::cout << "[" << sub2 << "]" << '\n';
    return 0;
}

运行结果如下。

[llo]
[]

分析:

在 "Hello" 中,从下标 2 往后只剩下 "llo" 这 3 个字符。虽然 text.substr(2, 100) 指定截取 100 个字符,但读到末尾就会自动停止,最终得到 "llo"。

而第二行的 text.substr(2, 0) 表示截取 0 个字符,因此返回了一个空字符串 ""。

2. 起始位置 pos 的有效范围

相比之下,第 1 个参数 pos 的范围限制就要严格得多了,主要分为以下 3 种情况:

  • pos < size():起始位置在有效字符下标范围内,正常向后截取。
  • pos == size():起始位置刚好落在末尾最后一个字符之后,此时调用依然合法,直接返回空字符串 ""。
  • pos > size():起始位置超出了允许范围,程序运行时会直接报出 std::out_of_range 越界错误并停止运行。

示例 4:检查起始位置的范围

#include <iostream>
#include <string>

int main() {
    std::string text = "Hello";

    std::string emptyStr = text.substr(text.size());
    std::cout << "[" << emptyStr << "]" << '\n';

    std::size_t pos = 10;
    if (pos <= text.size()) {
        std::cout << text.substr(pos) << '\n';
    } else {
        std::cout << "起始位置超出有效范围" << '\n';
    }
    return 0;
}

运行结果如下。

[]
起始位置超出有效范围

分析:

"Hello" 的长度是 5,所以 text.substr(text.size()) 相当于 text.substr(5)。因为起始下标刚好等于字符串长度,这次调用是合法的,最终得到了空字符串 ""。

后面定义的无符号下标 pos 等于 10,已经大于字符串长度 5 了。直接调用 text.substr(10) 会报越界错误,因此在动态计算下标时,我们可以先配合 if 语句,确认 pos <= text.size() 后再执行截取。

上一篇:

下一篇:

给站长反馈

绿叶网正在不断完善中,小伙伴们如果发现任何问题,还望多多给站长反馈,谢谢!

邮箱:lvyenet@vip.qq.com

「绿叶网」服务号
绿叶网服务号放大
关注服务号,微信也能看教程。
绿叶网服务号