程序员必须搞懂的换行符:\r、\n、\r\n 全解析
程序员必须搞懂的换行符:\r、\n、\r\n 全解析
在编程、文本处理、Git、日志系统或网络协议中,经常会看到这些字符:
1 | \r |
很多人知道它们和“换行”有关,但为什么会有这么多种?不同系统为什么不一样?工程中应该怎么处理?
本文会从 历史 → 系统差异 → 开发实践 → 常见坑 → 通用技巧 全面讲清楚。
一、什么是 \r 和 \n
在 ASCII 控制字符中:
| 字符 | 名称 | ASCII | 含义 |
|---|---|---|---|
\r |
Carriage Return | 13 | 回到当前行开头 |
\n |
Line Feed | 10 | 移动到下一行 |
\r:将光标移动到当前行最左边\n:将光标向下移动一行
这两个字符来自打字机时代。当时打印一行文字需要两个动作:
Carriage Return:打印头回到行首
Line Feed:纸张向上滚动一行
因此两个字符组合才能真正开始新的一行。 (GeeksforGeeks)
二、为什么会有 \r\n
在早期打印设备中:
1 | CR → 回到行首 |
如果只执行:
1 | LF |
打印头会停在原来的列位置。
例如:
1 | Hello |
因此很多系统使用:
1 | CR + LF |
也就是:
1 | \r\n |
表示真正的换行。 (维基百科)
三、不同操作系统的换行规则
由于历史演进,不同系统选择了不同的换行方式。
| 系统 | 换行符 |
|---|---|
| Linux / Unix | \n |
| macOS (OSX以后) | \n |
| Windows | \r\n |
| 旧 MacOS | \r |
示例:
Linux
1 | Hello\n |
Windows
1 | Hello\r\n |
Unix 系统选择 只用 LF,因为系统会自动把光标移到行首。 (ToolSG)
四、\r 的特殊用途
\r 其实不一定用于换行,它经常用于 覆盖当前行内容。
例如进度条:
1 | printf("Progress: 10%%\r"); |
终端效果:
1 | Progress: 30% |
很多 CLI 工具(npm、wget、curl)都是这么实现进度刷新。
五、为什么会出现 ^M
如果在 Linux 中打开 Windows 文件,经常看到:
1 | ^M |
例如:
1 | Hello^M |
原因:
1 | Windows: \r\n |
Linux 会把 \r 当成普通字符显示。
解决方法:
1 | dos2unix file.txt |
或
1 | sed -i 's/\r$//' file.txt |
六、编程语言中的换行
大多数语言已经做了兼容处理。
C / C++
1 | printf("Hello\n"); |
在 Windows 文本模式下:
1 | \n → \r\n |
自动转换。
但如果使用二进制模式:
1 | fopen("file.txt","wb") |
则不会自动转换。
Python
1 | open("file.txt","w") |
Python 会自动处理换行。
如果需要指定:
1 | open("file.txt","w", newline="\n") |
JavaScript / Node.js
通常直接使用:
1 | \n |
Node 在大多数情况下不会有跨平台问题。
七、网络协议为什么必须 \r\n
很多协议规定:
1 | CRLF = 行结束符 |
例如:
HTTP
1 | GET / HTTP/1.1\r\n |
其他协议
SMTP
FTP
Redis Protocol
如果只写 \n,某些服务器会解析失败。
八、Git 的换行问题
多人协作时最常见问题之一。
例如:
1 | LF → CRLF |
Git 会提示:
1 | LF will be replaced by CRLF |
原因:
Linux 使用
LFWindows 使用
CRLF
解决方案:
Windows
1 | git config --global core.autocrlf true |
Linux / macOS
1 | git config --global core.autocrlf input |
或者统一:
1 | .gitattributes |
1 | * text=auto eol=lf |
九、工程中最推荐的做法
现代软件工程基本遵循以下规则:
1 统一仓库换行
使用:
1 | LF (\n) |
原因:
Linux / macOS 默认
Docker / CI 默认
GitHub 默认
2 读取时兼容所有格式
解析文本时建议支持:
1 | \r\n |
例如 JS:
1 | text.split(/\r?\n/) |
3 写入时统一使用 \n
不要主动写:
1 | \r\n |
除非是:
Windows专用文件
网络协议
4 编辑器统一设置
例如 VSCode:
1 | LF |
右下角可以切换:
1 | CRLF / LF |
十、开发中的几个经典坑
1 Shell 脚本无法执行
如果脚本是 Windows 换行:
1 | #!/bin/bash\r |
Linux 会报错:
1 | bad interpreter |
解决:
1 | dos2unix script.sh |
2 Docker 构建失败
Docker 容器通常是 Linux 环境:
1 | CRLF → 执行失败 |
3 Git diff 全部变更
如果切换:
1 | CRLF → LF |
Git 会认为所有行都修改。
十一、最简单的记忆方式
1 | \r = 回车(回到行首) |
开发原则:
1 | 读取:兼容所有 |
十二、一个非常实用的工程口诀
很多团队内部会用一句话总结:
1 | 读宽松,写统一,协议严格 |
意思是:
1 | 读取:兼容 \r\n \n \r |
文章作者: kaxifa
更多内容: https://kaxifa.eu.org
