go 语言中默认的正则表达式 . 元字符不匹配换行符,即使启用 (?m) 多行模式也无效;需使用 (?s) 单行模式(dotall 模式)让 . 匹配包括 \n 在内的任意字符。
go 语言中默认的正则表达式 . 元字符不匹配换行符,即使启用 (?m) 多行模式也无效;需使用 (?s) 单行模式(dotall 模式)让 . 匹配包括 \n 在内的任意字符。
在 Go 中处理跨多行的 HTML 或自定义标签(如
要使 . 匹配换行符,必须启用 (?s) 标志(即 single-line 或 dotall 模式)。该标志让 . 可匹配任意 Unicode 字符,包括 \n、\r 等空白符。
✅ 正确写法如下:
func main() {
// 使用 (?s) 而非 (?m):s 表示 dotall,允许 . 匹配换行符
r := regexp.MustCompile(`(?s)<think>(.*?)</think>`)
const s = `That is
<think>
FOOBAR
</think>`
matches := r.FindStringSubmatch([]byte(s))
if len(matches) > 0 {
fmt.Printf("Matched: %s\n", strings.TrimSpace(string(matches)))
// 输出: Matched: <think>
// FOOBAR
// </think>
// 若只提取标签内内容(不含标签本身),用子组:
submatches := r.FindSubmatch([]byte(s))
if len(submatches) >= 2 {
content := strings.TrimSpace(string(submatches[1]))
fmt.Printf("Content only: %q\n", content) // "FOOBAR"
}
}
}
⚠️ 注意事项:
- (?s) 和 (?m) 可组合使用(如 (?sm)),但本例中仅 (?s) 必需;
- 建议使用非贪婪量词 .*? 替代 .*,避免跨标签匹配(例如当文本含多个
时,.* 会从第一个开始一直匹配到最后一个 ); - regexp.MustCompile 接收 string,但 FindStringSubmatch 返回 []byte;若需字符串结果,可配合 string() 转换并用 strings.TrimSpace 清理首尾空白;
- 对于结构化内容(如 XML/HTML),生产环境推荐使用专用解析器(如 golang.org/x/net/html),正则仅适用于简单、可控的模板场景。
总结:Go 正则中的 . 默认为“除换行符外任意字符”,启用 (?s) 是实现真正多行捕获的关键;理解 (?s) 与 (?m) 的职责分离,能避免大量调试陷阱。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











