用户在输入框里填写账号名或搜索词时,经常会在文字前后不小心多敲几个空格。如果不先清理掉这些多余的空格,后续在比对或查询数据时就容易出错。
在 C++ 中,std::string 没有提供现成的 trim() 函数。平时清理空格一般分为 2 种情况:一种是只去掉首尾两端的空格,保留句子中间的正常空格;另一种是把字符串里的所有空格全部删掉。
去除开头或末尾的空格
std::string 提供了 find_first_not_of() 和 find_last_not_of() 两个查找函数。我们只需要先找出非空格字符的边界下标,再配合 substr() 函数截取出来,就能去掉开头或末尾的空格。
语法:
std::size_t first = str.find_first_not_of(' ');
std::size_t last = str.find_last_not_of(' ');说明:
从英文意思上很容易记住:first_not_of 表示 “第一个不是……的字符”,last_not_of 表示 “最后一个不是……的字符”。这两个函数的具体作用如下:
- find_first_not_of(' '):从左往右查找 “第一个不是空格” 的字符,返回它的下标位置。
- find_last_not_of(' '):从右往左查找 “最后一个不是空格” 的字符,返回它的下标位置。
如果整个字符串里全都是空格,或者本来就是空字符串,找不到任何非空格字符,它们都会跟 find() 函数一样返回 std::string::npos。
示例 1:去除开头的空格
#include <iostream>
#include <string>
int main() {
std::string text = " Hello C++";
std::size_t first = text.find_first_not_of(' ');
if (first == std::string::npos) {
text = "";
} else {
text = text.substr(first);
}
std::cout << "[" << text << "]" << '\n';
return 0;
}运行结果如下。
[Hello C++]分析:
上面代码中,text.find_first_not_of(' ') 从左往右跳过开头的 3 个空格,找到第一个非空格字符 'H' 的下标 3。接着调用 text.substr(first) 从下标 3 截取到末尾,就把开头的空格去掉了。
如果原字符串里全都是空格,查找结果就会等于 std::string::npos,此时 if 分支会直接把 text 设为空字符串 "",避免残留空格。
同理,如果想要去除字符串末尾的空格,只需要使用 find_last_not_of(' ') 找到最后一个非空格字符的位置即可。下面我们来看一个例子。
示例 2:去除末尾的空格
#include <iostream>
#include <string>
int main() {
std::string text = "Hello C++ ";
std::size_t last = text.find_last_not_of(' ');
if (last == std::string::npos) {
text = "";
} else {
text = text.substr(0, last + 1);
}
std::cout << "[" << text << "]" << '\n';
return 0;
}运行结果如下。
[Hello C++]分析:
在这个例子中,text.find_last_not_of(' ') 从右往左跳过末尾的 3 个空格,找到最后一个非空格字符 '+' 的下标 last,其值为 8。
可能有些小伙伴会问:为什么截取时要写成 text.substr(0, last + 1),要在 last 后面加 1 呢?因为下标是从 0 开始计算的,从下标 0 到下标 8 一共有 8 + 1(共 9)个字符,而 substr() 的第 2 个参数要求的正是字符个数。
同时去除首尾两端的空格
在实际开发中,更常见的需求是同时去掉字符串开头和末尾的空格,只保留中间的有效内容,比如把 " Hello lvyenet " 清理成 "Hello lvyenet"。
我们可以把上面两个查找函数结合起来:先找出第一个非空格字符的下标 first,再找出最后一个非空格字符的下标 last。
由于首尾这两个非空格字符本身都要保留,就像看书时从第 3 页读到第 6 页一共读了 6 - 3 + 1 = 4 页一样,两个下标相减之后还要加 1,算出来的 last - first + 1 才是中间有效内容的字符个数。
示例 3:去除首尾两端的空格
#include <iostream>
#include <string>
int main() {
std::string text = " Hello lvyenet ";
std::size_t first = text.find_first_not_of(' ');
if (first == std::string::npos) {
text = ""; // 全是空格时设为空串
} else {
std::size_t last = text.find_last_not_of(' ');
text = text.substr(first, last - first + 1);
}
std::cout << "[" << text << "]" << '\n';
return 0;
}运行结果如下。
[Hello lvyenet]分析:
在 " Hello lvyenet " 中,首字母 'H' 的下标 first 为 2,尾字母 't' 的下标 last 为 14,算出有效长度 last - first + 1 为 13。
接着调用 text.substr(2, 13),首尾两端的空格就被干净去掉了,而两个单词中间的正常空格依然保留了下来。
提示 如果字符串首尾还可能包含 \t、\n、\r 等转义字符,可以把查找参数换成字符串 " \t\n\r",一次性把首尾的各种空白字符全部清理干净。
C++20 删除所有空格
前面的做法只清理首尾两端,保留了字符串内部的空格。如果我们的需求是把字符串首尾和中间出现的所有空格全部删掉,从 C++20 标准开始,<string> 头文件直接提供了 std::erase() 函数,一行代码就能删除字符串中所有指定的字符。
语法:
std::erase(str, ' ');说明:
调用 std::erase(str, ' ') 会直接在原字符串 str 上把所有的空格字符 ' ' 全部删除,字符串的长度也会随之缩短。
示例 4:删除所有空格
#include <iostream>
#include <string>
int main() {
std::string text = " 2026 - 10 - 23 ";
std::erase(text, ' ');
std::cout << "[" << text << "]" << '\n';
return 0;
}运行结果如下。
[2026-10-23]分析:
" 2026 - 10 - 23 " 不仅首尾有空格,连字符 "-" 的左右两侧也都有空格。执行 std::erase(text, ' '); 后,字符串里所有的空格都被直接删除,变成了紧凑的 "2026-10-23"。
常见问题
1. text.erase() 和 std::erase() 名字都叫 erase,它们有什么区别?
这两个函数的名字虽然相同,但调用方式和删除规则不一样,小伙伴们不要搞混了:
text.erase(pos, count):属于 std::string 的成员函数,按 “下标位置和字符个数” 删除。比如 text.erase(0, 3) 表示从下标 0 开始连续删除 3 个字符。
std::erase(text, ' '):属于 C++20 新增的标准库函数,按 “字符内容” 删除,会把 text 里所有的 ' ' 全部删掉。同理,如果第 2 个参数传入 '-',就会删掉字符串里所有的连字符。
