std::string::find + substr 是最可控的按行切分方式,能精准控制起始位置、处理空行和尾部换行符;正确更新 pos 为 found + 1 避免漏行;大数据量去重时 vector+sort+unique 比 set insert 快 2–3 倍,但需排序且内存峰值更高;混合换行符需先归一化。

std::string::find + std::string::substr 是最可控的按行切分方式
直接用 std::getline 读流虽然方便,但无法对已有字符串做原地分割;而 std::string::find 配合 std::string::substr 能精准控制起始位置、处理空行和尾部换行符,且不依赖 I/O 流状态。
常见错误是写成 pos = s.find('\n', pos + 1) —— 这会跳过连续的 \n,导致漏行。正确做法是每次找到后更新 pos 为 found + 1,再从该处继续找:
size_t pos = 0, found;
while ((found = s.find('\n', pos)) != std::string::npos) {
lines.insert(s.substr(pos, found - pos)); // 插入到 set/multiset
pos = found + 1;
}
if (pos <h3>用 std::set<:string> 还是 std::multiset<:string>?取决于是否允许重复</:string></:string>
</h3><p>如果输入行可能重复(如日志中多条相同错误),<code>std::set</code> 会静默丢弃后续重复项,而 <code>std::multiset</code> 保留全部 —— 两者插入复杂度都是 <code>O(log n)</code> 每次,但后者内存略高、遍历时顺序一致但含重复。</p><p>注意:若需区分大小写或按字典序以外规则排序(如按长度),必须显式传入比较器:</p>
-
std::set<:string std::greater>> lines;</:string>→ 降序 -
std::set<:string auto a const b return a.size b.size></:string>→ 按长度升序
省略比较器时默认用 std::less<:string></:string>,即字典序升序。
避免 std::stringstream + std::getline 的隐式拷贝开销
有人习惯把字符串塞进 std::stringstream 再用 std::getline,这会触发多次小内存分配和拷贝 —— 尤其当单行很短、总行数很多时,性能明显劣于 find/substr 方案。
实测对比(10 万行、平均每行 20 字符):
-
find + substr:约 1.2 ms -
stringstream + getline:约 4.7 ms(含内部缓冲管理开销)
更关键的是:std::stringstream 对 \r\n 不敏感,遇到 Windows 换行会把 \r 留在行末;而手动 find 可统一处理 "\r\n" 或 "\n":
found = s.find_first_of("\r\n", pos);
if (found != std::string::npos && s[found] == '\r' && found + 1 <h3>std::vector<:string> + std::sort 后去重,比直接用 set 更快?</:string>
</h3><p>当行数极大(>100 万)、且多数行唯一时,先 push_back 到 <code>std::vector</code>,再 <code>std::sort</code> + <code>std::unique</code>,通常比逐个 insert 到 <code>std::set</code> 快 2–3 倍 —— 因为 vector 的连续内存 + sort 的 cache 友好性碾压红黑树的指针跳转。</p><p>但要注意:</p>
-
std::unique只移除相邻重复项,必须先sort - 去重后若需保持原始顺序,此法不可用
- 内存峰值更高:vector 存全量,set 只存去重后
示例片段:
std::vector<:string> tmp; // ... fill tmp with lines via find/substr ... std::sort(tmp.begin(), tmp.end()); auto last = std::unique(tmp.begin(), tmp.end()); tmp.erase(last, tmp.end());</:string>
真正难处理的是混合换行符(\n、\r\n、甚至孤立 \r)和嵌入空字符的场景 —— 这时得先 normalize 换行符,再切分,否则 find('\n') 会漏掉纯 \r 分隔的行。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











