c++oding="utf-8" ?>
最直接的方法是用 std::regex_replace 和正则 "-{2,}" 替换为 "-",但需注意旧版 libstdc++ 兼容性问题;若受限,则手写双指针遍历,保留首个连字符并跳过后续连续的,正确处理边界如空串或全连字符。

用 std::regex_replace 一次性压缩连续连字符
最直接的思路是把两个及以上连续的 - 全部替换成单个 -,但要注意:不能误删开头或结尾的孤立连字符(比如 "-abc--def--" 应变成 "-abc-def-")。正则 "-{2,}" 能精准匹配 ≥2 个连续连字符,配合 std::regex_replace 最简洁:
std::string s = "a---b----c";
s = std::regex_replace(s, std::regex("-{2,}"), "-");
// 结果: "a-b-c"
⚠️ 注意:std::regex 在某些旧版 libstdc++(如 GCC 4.9)中存在性能问题或不完全支持;若目标环境受限,优先考虑手写循环。
手写遍历更可控,避免正则依赖和边界错误
手动扫描能完全规避正则兼容性问题,也更容易控制“保留首尾连字符”的逻辑。关键不是“删掉多余”,而是“只保留第一个连字符,跳过后续连续的”:
- 用两个指针:一个读位置
read,一个写位置write - 遇到非
-字符,直接复制;遇到-,检查前一个字符是否也是-—— 只有当它不是连续第二个时才写入 - 特别注意空字符串和全连字符输入(如
"-----"→ 应为"-")
std::string compress_dashes(const std::string& s) {
if (s.empty()) return s;
std::string res;
res.reserve(s.size());
res += s[0]; // 总是保留第一个字符
for (size_t i = 1; i
<h3>为什么不用 <code>erase</code> + <code>find</code> 循环?</h3>
<p>有人会想用 <code>s.erase(pos, len)</code> 反复删除连续段,但实际容易出错:</p>
- 每次
erase后字符串长度和索引偏移变化,find位置需重新计算,极易越界或漏删 - 多次内存重分配影响性能,尤其长字符串
- 无法优雅处理边界:比如
"--a--"中开头两个-应缩为一个,但若从左往右找"--"并删,可能误删成"-a--"(只删了一次)
除非明确只要删中间的冗余(如强制要求首尾必须是字母),否则不推荐这种思路。
区分场景:要“压缩”还是“清理”?
“去掉多余连字符”在不同业务中含义不同:
- 文件名规范化(如 URL slug):通常要求首尾无连字符,且不连续 —— 需额外 trim 和前后校验
- 命令行参数解析(如
--verbose):连字符本身有语义,不能动,这里的问题不适用 - 用户输入清洗:可能还需同时处理空格、下划线等,建议统一用状态机而非仅盯连字符
真正难的不是怎么写那几行代码,而是确认“多余”的定义是否包含首尾、是否允许单独出现在两端、是否和其他分隔符共存——这些逻辑一旦定错,后面所有实现都白搭。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











