一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

C++中如何实现字符串的按行快速去重处理

时间:2026-06-23 08:27:53 编辑:袖梨 来源:一聚教程网

std::set直接存std::string不适合按行去重,因换行符处理不一致(如getline剥离n而>>不剥离)及空行/空白行语义模糊;应先用find_first/last_not_of清洗首尾空白(含r),再用unordered_set去重并配合vector保序。

为什么 std::set 直接存 std::string 不适合按行去重?

因为文件读入的每行通常带换行符("n""rn"),而不同平台、不同读取方式(std::getline vs fgets)对换行符的处理不一致。直接丢进 std::set 会导致看似相同的两行被当作不同字符串——比如 "hellon""hello"getline 自动剥离了 n,但若用 std::cin >> 就不会)。更麻烦的是,如果原始数据含空行或全空白行,它们也参与比较,但用户往往希望“逻辑空行”视为相同。

怎么用 std::unordered_set 配合规范化处理?

核心是统一清洗:先去除行首尾空白(包括 r),再判断是否为空。这样能兼容 Windows/Linux 换行差异,也避免空格干扰去重。

  • std::getline 是首选,它自动剥离 n(或 rn),返回不含换行符的字符串
  • std::string::find_first_not_of(" trn")find_last_not_of 截取有效内容;全空白则得到空串
  • 把清洗后的字符串插入 std::unordered_set<:string></:string>,O(1) 平均插入/查找,比 std::set
  • 若需保持原始输入顺序输出去重结果,额外用 std::vector 记录首次出现的行(配合 unordered_set::insert 的返回值判断)

示例关键片段:

std::unordered_set<std::string> seen;std::vector<std::string> unique_lines;<p>std::string line;while (std::getline(std::cin, line)) {// 去首尾空白(含 r)auto start = line.find_first_not_of(" trn");if (start == std::string::npos) continue; // 空行跳过auto end = line.find_last_not_of(" trn");std::string clean = line.substr(start, end - start + 1);</p><pre class='brush:php;toolbar:false;'>if (seen.insert(clean).second) { // .second 为 true 表示新插入    unique_lines.push_back(std::move(clean));}

}

立即学习“C++免费学习笔记(深入)”;

大文件下内存和性能怎么控?

纯内存方案在几百 MB 级文本上就容易爆内存(每个 std::string 有小开销,unordered_set 负载因子高时会 realloc)。真正快速的“按行去重”必须考虑外排或流式哈希。

  • 若只要去重后行数,不用保留内容:用 std::unordered_setstd::string_view(C++17),但注意生命周期——必须确保源缓冲区不释放(比如整行读到 std::string 再转 view)
  • 超大文件(GB 级):改用分块读 + SHA256 哈希(std::hash 对长字符串碰撞率偏高,不推荐),哈希值存 std::unordered_set<uint64_t> 节省内存
  • 极端场景(内存极紧):用 Bloom Filter 预过滤,再落盘比对;但会引入误判,仅适用于允许少量漏重的场景

Windows 下读取文本文件时的 r 坑怎么绕?

std::ifstream 默认以文本模式打开,Windows 下会自动将 rn 转成单个 n,所以 getline 返回的字符串不含 r。但如果你用二进制模式(std::ios::binary)读,或从管道/网络接收数据,r 就可能残留——此时清洗步骤里必须显式剔除 r,不能只靠 getline

  • 不要依赖 line.pop_back()r:有些行末是 n,有些是 rn,有些甚至只有 r(老 Mac 格式)
  • 统一用 find_last_not_of(" trn") 安全截断,比条件判断更鲁棒
  • 如果原始数据来自 HTTP 响应体或日志采集,很可能混用换行风格,清洗必须做

实际写的时候,最容易被忽略的是:清洗逻辑必须和业务语义对齐。比如日志中 "error: timeout""error: timeout "(末尾空格)是否算重复?有些场景要算,有些要严格字节相等。别默认“去空格”,先想清楚需求再写清洗。

热门栏目