
本文介绍如何在 go 中利用 `regexp` 包精准匹配并替换嵌套的 `
在 Go 模板预处理或 HTML 内容清洗过程中,常需剥离特定自定义标签(如 <dxh>),但保留其内部的 Go 模板语法(如 {{4567}})。由于 <dxh> 标签可能带有任意属性、换行和嵌套子元素,直接用字符串截取不可靠,而正则表达式配合非贪婪匹配与捕获组是简洁有效的解决方案。
关键在于设计一个能应对以下情况的正则模式:
- 支持 <dxh> 开始标签含任意属性(如 r="4" spans="1:15");
- 允许跨行匹配(需启用 (?s) 单行模式,使 . 匹配换行符);
- 非贪婪地匹配到第一个 {{...}} 模板内容(避免误吞后续内容);
- 精确匹配闭合 </dxh>,确保只替换完整标签对。
以下是完整可运行示例:
package main
import (
"fmt"
"regexp"
)
func main() {
// 编译正则:匹配 <dxh...> 开始标签 → 非贪婪跳过任意内容 → 捕获 {{...}} → 匹配 </dxh>
re := regexp.MustCompile(`(?s)<dxh[^>]*>.*?({{[^}]*}}).*?</dxh>`)
input := `aaa<div><dxh r="4" spans="1:15"><c r="A4" s="7"><v>{{4567}}
</v></c><c r="B4" t="s" s="7"><v>11</v></c><c r="C4" t="s" s="7"><v>12</v>
</c><c r="M4" t="s" s="8"><v>20</v></c></dxh>aaa</div>bbb<dxh>{{12345}}
</dxh>amrambler`
// 使用 $1 引用第一个捕获组(即 {{...}} 内容),替换整个 <dxh>...</dxh> 片段
result := re.ReplaceAllString(input, "$1")
fmt.Println(result)
// 输出:aaa<div>{{4567}}aaa</div>bbb{{12345}}amrambler
}⚠️ 注意事项:
立即学习“前端免费学习笔记(深入)”;
- 此方案不适用于嵌套 <dxh> 标签(如 <dxh>...<dxh>{{inner}}</dxh>...</dxh>),因正则无法处理任意深度嵌套——此时应改用 HTML 解析器(如 golang.org/x/net/html);
- {{[^}]*}} 假设模板变量中不含 },若存在复杂表达式(如 {{.User.Name}}),建议升级为 {{[^}]*\}[^}]*}} 或更鲁棒的解析逻辑;
- re.ReplaceAllString 仅替换首次匹配。若需全局替换所有 <dxh> 标签,请改用 re.ReplaceAllString(input, "$1") —— 实际上该方法默认全局替换(ReplaceAll* 系列均为全局),但需确保正则本身未限制匹配次数;
- 若输入含多个 {{...}} 在同一 <dxh> 内,当前正则仅捕获第一个;如需全部提取,应改用 FindAllStringSubmatch 配合循环处理。
总结:对于结构相对固定的自定义标签清洗任务,Go 的 regexp 提供了高效、轻量的解决方案。合理运用 (?s)、非贪婪量词 .*? 和捕获组 $1,即可安全剥离外层标签,精准提取模板内容。











