
本文详解如何在 Go 中正确使用 regexp 删除字符串中所有空行及仅含空白字符(空格、制表符等)的行,重点解决 ^ 和 $ 默认不按行匹配的问题,并提供健壮、可落地的正则方案与完整示例代码。
本文详解如何在 go 中正确使用 `regexp` 删除字符串中所有空行及仅含空白字符(空格、制表符等)的行,重点解决 `^` 和 `$` 默认不按行匹配的问题,并提供健壮、可落地的正则方案与完整示例代码。
在 Go 的 regexp 包中,^ 和 $ 默认仅匹配整个输入字符串的开头和结尾,而非每一行的起止位置——这与许多其他语言(如 Python、JavaScript)的默认行为不同。若要实现“按行处理”,必须启用 多行模式(Multiline Mode),即通过内联标志 (?m) 显式开启。
✅ 正确写法如下:
re := regexp.MustCompile(`(?m)^\s*$`)
其中 (?m) 启用多行模式后,^ 将匹配每个换行符 \n(或 \r\n)之后的位置(即每行开头),$ 则匹配换行符之前的位置(即每行结尾)。此时 \s* 可安全匹配该行内全部空白字符(包括空格、制表符 \t、垂直制表符 \v、换页符 \f、回车符 \r 等)。
⚠️ 但需注意两个关键细节:
\s包含换行符:Go 中\s等价于[\t\n\f\r ],会意外匹配\n或\r,导致正则跨越行边界,破坏按行逻辑。因此,若目标仅为“行内空白”,推荐改用[ \t](仅空格+制表符)或更精确的[\t\p{Zs}](含 Unicode 分隔空格)。$不消耗换行符:$是零宽断言,它只定位到行尾,不匹配也不删除换行符本身。若直接用(?m)^\s*$替换为空字符串,原换行符仍保留,可能造成多余空行残留或行间距异常。
为此,一个生产就绪的正则应同时处理两类情况:
- 匹配并清除“空行 + 其后的换行符”:
(?m)^\s*$[\r\n]* - 匹配并清除“末尾连续换行符 + 后续纯空白 + 字符串真正结尾”:
[\r\n]+\s+\z
综合后的完整解决方案如下:
package main
import (
"fmt"
"regexp"
)
func removeBlankLines(s string) string {
// 安全匹配:空行(含纯空白)及其换行符;兼顾末尾空行
re := regexp.MustCompile(`(?m)^\s*$[\r\n]*|[\r\n]+\s+\z`)
return re.ReplaceAllString(s, "")
}
func main() {
input := `
test
test
`
result := removeBlankLines(input)
fmt.Printf("原始:\n%q\n", input)
fmt.Printf("结果:\n%q\n", result)
// 输出: " test \n test "
}? 关键说明:
-
[\r\n]*显式捕获行尾换行符(0次或多次),确保删除整行; -
[\r\n]+\s+\z专治文件末尾的空行:先匹配 1+ 个换行符,再匹配后续空白,最后用\z锚定到字符串绝对末尾(\z比$更严格,避免误匹配); - 若输入含 Windows 风格
\r\n,该正则仍能正确处理; - 如需保留单个换行符作为段落分隔(避免多段合并),可将替换内容改为
"\n"并添加去重逻辑。
总结:Go 正则的 ^/$ 行级匹配必须显式启用 (?m);删除空行务必同时处理换行符;优先使用 [ \t] 替代 \s 提升语义准确性;对末尾边界场景,\z 是比 $ 更可靠的选择。

















