按行反转是将每行内部字符顺序翻转而保持行序不变;需用std::string_view定位换行符逐行处理,注意兼容\r\n及末尾无换行符的最后一行。

什么是“按行反转”?先明确操作边界
按行反转不是把整个字符串倒序,而是把每行内部字符顺序翻转,同时保持行与行的顺序不变。比如输入 "abc\ndef\nghi",期望输出是 "cba\nfed\nihg"。如果误用 std::reverse 作用于整个字符串,会得到 "ihg\nfed\ncba"——行序也反了,这是最常见的理解偏差。
关键判断点:你手里的是单个 std::string,还是已按行切分好的 std::vector<:string></:string>?处理方式完全不同。
用 std::string_view + 手动找换行符逐行处理
适合内存敏感或避免拷贝的场景,尤其当原始字符串很大、但行数不多时。核心是不拆分原串,只定位 '\n' 和 '\r\n'(Windows 换行需兼容)。
实操建议:
- 用
std::string_view sv = input;包装原字符串,避免额外复制 - 循环调用
sv.find('\n'),每次取sv.substr(0, pos)作为当前行(不含换行符) - 对子串调用
std::reverse,再拼回结果;注意保留原换行符位置 - 别忽略末尾无换行符的“最后一行”,它不会被
find('\n')捕获,需单独处理
std::string reverse_lines(const std::string& s) {
std::string out;
out.reserve(s.size()); // 预分配避免多次 realloc
size_t start = 0;
size_t pos = 0;
while ((pos = s.find('\n', start)) != std::string::npos) {
std::string line = s.substr(start, pos - start);
std::reverse(line.begin(), line.end());
out += line + '\n';
start = pos + 1;
}
// 处理最后一行(无 \n 结尾)
if (start <h3>用 <code>std::getline</code> + <code>std::vector</code> 分行再合并</h3><p>更直观、容错性好,适合逻辑优先、性能要求不极致的场合。自动处理 <code>\r\n</code> 和 <code>\n</code> 差异(<code>std::getline</code> 默认丢弃 <code>\n</code>,不带 <code>\r</code>)。</p><p>容易踩的坑:</p>
-
std::getline读到\r\n时,\r会留在行末,导致反转后变成"\r"在开头——若源文件是 Windows 格式,需手动 strip'\r' - 不要直接对
std::istringstream连续调用getline后立即reverse,因为std::string的 move 语义可能让后续迭代失效;建议先存入std::vector - 合并时记得补回换行符,否则所有行会挤成一行
性能和边界情况必须检查的三点
实际项目中出问题,往往卡在这几个地方:
- 空字符串或只含换行符(如
"\n\n"):确保循环能退出,且不访问s.substr(pos+1)越界 - 超长行(百万字符):用
std::reverse是 O(n),但频繁substr可能触发多次堆分配;可改用迭代器原地反转,避免中间std::string构造 - 嵌入空字符
'\0':C++std::string允许含\0,但std::getline会停在第一个\0——此时必须用 find 方式,不能依赖流
最麻烦的其实是换行符不统一。真实日志或用户输入里,\n、\r\n、甚至 \r(古 Mac)可能混在一起。如果业务要求严格保真,得先 normalize 换行符,或者写一个能识别三种结尾的 find_next_line 辅助函数。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











