std::unique只能压缩连续重复空格,因其仅移除相邻重复元素;需配合erase使用,且默认==谓词已满足空格压缩需求。

为什么std::unique不能直接删掉所有重复空格?
std::unique只移除「相邻重复元素」,不是全局去重。它把连续重复的空格压缩成一个,但前提是这些空格必须紧挨着。如果字符串是"a b c"(中间有单空格、双空格、三空格),std::unique会把" "变成" "," "也变成" "——这正是我们需要的效果。但它不会动非连续的空格,比如"a b c"里的三个单空格本来就不连续,所以一个都不会少。
关键点在于:std::unique操作的是迭代器范围,它不删除元素,只是把「保留项」往前挪,返回一个新逻辑终点迭代器;真正删除得靠erase配合这个迭代器。
- 必须传入
begin()和end()构成的左闭右开区间 - 不能对
std::string直接用std::unique而不接erase,否则只是内存乱序,长度不变 -
std::unique第三个参数是二元谓词,判断“是否该合并”,默认用==,对空格完全够用
正确组合erase + unique压缩连续空格
一行写法最常用,也最安全:
str.erase(std::unique(str.begin(), str.end(), [](char a, char b) { return a == ' ' && b == ' '; }), str.end());
但其实没必要写lambda——默认==就满足需求,更简洁:
str.erase(std::unique(str.begin(), str.end()), str.end());
注意:这行代码只会压缩连续空格,不会动其他字符,也不会把多个分散空格变一个。比如"x y z" → "x y z"(两个空格→一个,单空格保留)。
- 如果想把「所有空格」(不管连不连续)都缩成一个,得先用
std::replace或循环预处理,再unique,但那是另一类需求 - 对UTF-8字符串慎用——
std::string按字节操作,空格是ASCII 32,没问题;但中文等多字节字符里混空格时逻辑不变 - 性能上,
unique是O(n),erase后续移动也是O(n),整体线性,无额外分配
常见错误:误用std::remove_if代替unique
有人写str.erase(std::remove_if(str.begin(), str.end(), ::isspace), str.end()),结果所有空格全没了——这不是“压缩”,是“清空”。remove_if删的是满足条件的每一个元素,不管连不连续。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
另一个典型错法是漏掉erase:
std::unique(str.begin(), str.end()); // ❌ 没用!str长度没变,后面可能有脏数据
或者传错区间:
str.erase(std::unique(str.begin(), str.begin() + 5), str.end()); // ❌ 只处理前5个字符
-
std::unique返回的是“新逻辑尾”,必须和原end()配对使用erase - 不要对
const std::string调用,编译不过 - 在循环里反复对同一字符串调用
unique+erase没意义,一次就够了
需要保留首尾空格?那就不能直接unique
上面所有写法都会压缩开头/结尾的连续空格。比如" hello world " → " hello world "。如果业务要求首尾空格只删多余、中间才压缩,就得拆开处理:
auto start = str.find_first_not_of(' ');
auto end = str.find_last_not_of(' ');
if (start == std::string::npos) {
str.clear();
} else {
std::string mid = str.substr(start, end - start + 1);
mid.erase(std::unique(mid.begin(), mid.end()), mid.end());
str = std::string(start, ' ') + mid + std::string(str.length() - end - 1, ' ');
}
这段逻辑稍重,但清晰表达了意图:先切出有效内容,压缩中间,再补回首尾空格数。实际项目中,如果首尾空格语义重要(比如日志对齐、格式化输出),跳过这一步容易引发下游解析异常。
真正容易被忽略的,是空字符串或全空格字符串的边界情况——find_first_not_of返回npos时必须单独清空,否则substr会抛异常。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










