推荐用 std::istringstream 拆词后逐个比较相邻词去重,避免原地删除越界;对带标点词需提取 alnum token 作比较键但保留原始词输出;std::unique 仅适用于 vector 而非 string 字符;性能敏感时宜用 vector 缓存再拼接。

用 std::istringstream 拆词再比对,最稳
直接操作 std::string 做原地删除容易越界或漏判,尤其当重复单词长度不同时(比如 “hello hello hello world”)。推荐先按空格切词,再逐个比较相邻词是否相等——这是语义上“连续重复单词”的准确含义。
注意:这里“单词”指由空白分隔的非空子串,不处理标点;若需保留标点逻辑,得先做词法清洗。
- 用
std::istringstream读取每个词,避免手写find/substr出错 - 只保留和前一个词不同的词,跳过连续重复项
- 结果拼接时注意单词间单个空格,末尾不留空格
std::string removeConsecutiveDuplicates(const std::string& s) {
std::istringstream iss(s);
std::string word, result;
std::string prev;
while (iss >> word) {
if (word != prev) {
if (!result.empty()) result += " ";
result += word;
}
prev = word;
}
return result;
}
遇到带标点的词怎么办?先剥离再恢复
如果输入是 “Hello, Hello, world!”,上面的代码会把 "Hello," 和 "Hello," 当作相同词(其实它们一样),但更常见的是 "Hello" 和 "Hello," 被视为不同——这不是你想要的“重复单词”。
这时候不能硬改比较逻辑,而是预处理:提取纯字母/数字部分用于判断重复,但保留原始词用于输出。
- 用
std::isalnum扫描每个词,提取 token 作比较键(如"Hello,"→"Hello") - 仍用原始
word拼入结果,保证格式不变 - 注意空词过滤:全标点的字符串(如
"!!! !!")会被忽略
std::unique 不能直接用在字符串上
有人想用 std::unique 配合 std::vector<:string></:string>,这可行,但别误以为能对 std::string 的字符调用它——std::unique 去重的是连续相同元素,而字符串里连续相同的是字符,不是单词。
- 对
std::vector<:string></:string>调用std::unique是对的,但必须先用std::istringstream拆好词存进去 - 别写
std::unique(s.begin(), s.end())—— 这删的是重复字母,比如 “aa bb cc” 变成 “a b c” - 拆词后用
std::unique本质和手写循环一样,没省多少事,还多一次内存拷贝
性能敏感时避免多次字符串拼接
高频调用或超长文本下,result += word 可能触发多次内存重分配。可预先估算容量(比如按原字符串长度粗略估计词数),或改用 std::vector<:string></:string> 缓存再一次性拼接。
- 用
reserve()对result预留空间(例如result.reserve(s.length()))有帮助,但不保证完全避免重分配 - 更可靠的做法:先 push_back 到 vector,最后用
std::accumulate或循环加空格拼接 - 如果输入确定短小(+=
真正容易被忽略的,是“连续重复”的定义边界——它只看相邻位置,不跨空格、不跨标点、不忽略大小写。哪怕只是首字母大小写不同("The the"),默认也不算重复,这点必须按需明确是否要 tolower 统一。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











