正确做法是先统一换行符再用strings.split,或用strings.fieldsfunc按'\n'和'\r'切分;需保留空行则replaceall后split;大数据量推荐bufio.scanner,它自动兼容各换行符且高效。

用 strings.Split 按换行符分割字符串,但要注意换行符差异
Go 中最直接的方案是 strings.Split(s, "\n"),但它只认 \n,对 Windows 的 \r\n 或旧 Mac 的 \r 无效。实际文本(尤其来自文件、HTTP 响应或用户输入)往往混用换行符,直接切会把 \r\n 当成一行末尾带 \r 的脏数据。
正确做法是先统一换行符再切,或改用更鲁棒的方式:
-
strings.ReplaceAll(s, "\r\n", "\n")后再strings.Split(..., "\n") - 或一步到位:
strings.FieldsFunc(s, func(r rune) bool { return r == '\n' || r == '\r' })—— 它把\n和\r都当分隔符,自动跳过连续分隔符(比如\r\n\r\n不会产生空字符串) - 注意:
strings.FieldsFunc会丢弃首尾空白行;若需保留空行,必须用ReplaceAll+Split组合
从 strings.Reader 按行读取,适合大字符串或流式处理
如果字符串很大,或你后续要逐行做解析(比如 CSV、日志),别一次性全切进内存,用 bufio.Scanner 更高效且可控:
reader := strings.NewReader(s)
scanner := bufio.NewScanner(reader)
for scanner.Scan() {
line := scanner.Text() // 不含换行符
// 处理 line
}
if err := scanner.Err(); err != nil {
// 处理读取错误(如行超长)
}
bufio.Scanner 默认单行上限 64KB,超长会报 bufio.Scanner: token too long。真有超长行,得提前调 scanner.Buffer(make([]byte, 0, 1MB), 1MB) 扩容。
它自动兼容 \n、\r\n、\r,无需手动处理换行符差异。
strings.Split vs bufio.Scanner:选哪个?
看场景:
- 只是简单切几行、后续要随机访问某一行 → 用
strings.Split(配合换行符预处理) - 字符串可能很大、或你要边读边处理(比如过滤、转换)、或行数不确定 → 用
bufio.Scanner - 需要保留空行且不想手写循环 →
strings.ReplaceAll(s, "\r\n", "\n").ReplaceAll("\r", "\n")后strings.Split(..., "\n") - 想一行行读但不用
Scanner(比如要自己控制缓冲区)→ 用bufio.NewReader+ReadString('\n'),但得自己处理\r和 EOF 边界
真实场景中容易漏掉的点
Windows 文件保存的文本常以 \r\n 结尾,但 Go 的 os.ReadFile 返回原始字节,不会帮你 Normalize。很多人测试时用 Linux 生成的字符串没问题,一到生产环境就读出带 \r 的行,导致 JSON 解析失败或 trim 不干净。
另外:strings.Split 对空字符串 "" 返回 []string{""},而 bufio.Scanner 在空输入下不进入循环 —— 这个差异在单元测试里很容易被忽略。
真正麻烦的不是“怎么切”,而是“切完之后每行是否干净”。建议所有按行处理的逻辑,开头加一句 strings.TrimSpace(line),比反复调试换行符更省时间。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











