最简超链接结构可用正则匹配行内式[text](url)和自动链接,但参考式需ast解析;推荐用goldmark visitor遍历*ast.link节点提取url与文本。

用正则匹配最简超链接结构
Go 标准库没有内置 Markdown 解析器,直接提取链接最常用也最可控的方式是正则。但注意:Markdown 超链接有多种语法(行内式、参考式、自动链接),regexp 只能可靠覆盖常见行内式 [text](url) 和自动链接 <https:></https:>。
容易踩的坑是写太宽泛的正则,比如 href="[^"]*" —— 这会误抓 HTML 片段,而原始字符串只是纯 Markdown 文本,不含标签。
- 推荐用这个正则提取
[...](...):`\[([^\]]+)\]\(([^)]+)\)`(注意转义) - 补充匹配自动链接:
`]+)>`,但需过滤掉邮箱(如<user></user>),只保留以http或ftp开头的 - 参考式链接(如
[foo][bar]+ 底部定义)无法靠正则安全提取,必须用完整解析器
用 blackfriday/v2 解析并遍历 AST
如果 Markdown 字符串可能含复杂嵌套(如链接在强调内、链接含转义括号)、或你已依赖 blackfriday/v2,走 AST 更稳健。它把文档转成节点树,ast.Link 节点天然对应超链接。
关键点:不要用 blackfriday.Run()(输出 HTML),而是调用 parser.Parse() 得到根节点,再递归查找 *ast.Link 类型节点。
-
link.Destination是原始 URL(未解码),link.Text是链接文本节点,需再调用ast.Render或手动提取文本 - 注意
blackfriday/v2已归档,新项目建议改用github.com/yuin/goldmark - goldmark 需注册自定义 visitor,比 blackfriday 略啰嗦,但扩展性更好
goldmark 中用 Visitor 提取链接
goldmark 是当前最活跃的 Go Markdown 库,Visitor 模式适合精准提取。你需要实现 ast.WalkFunc,在进入每个节点时判断是否为 *ast.Link。
示例核心逻辑:
ast.Walk(doc, func(node ast.Node, entering bool) ast.WalkStatus {
if entering && ast.Kind(node) == ast.KindLink {
link := node.(*ast.Link)
url := string(link.Destination)
text := extractText(link) // 自行实现:递归读子节点的 TextSegment
links = append(links, struct{ URL, Text string }{url, text})
}
return ast.WalkContinue
})
-
link.Destination是[]byte,必须用string()转换 - 链接文本可能含强调、代码等子节点,
extractText不能只读link.FirstChild,要遍历整个子树 - goldmark 默认不解析自动链接(
<https:></https:>),需启用extension.WithAutoURLs()
要不要处理相对链接和锚点?
提取出的 URL 多是原始字符串,是否需要补全、去重、过滤,取决于你的使用场景。
- 若用于爬虫或预检,建议用
url.Parse判断有效性:u, err := url.Parse(raw),再检查u.Scheme != "" - 相对路径(如
/about、../img.png)需结合基础 URL 补全,用base.ResolveReference(u) - 锚点(
#section1)不是独立资源,是否保留取决于下游用途;多数情况下应过滤掉纯锚点 - 重复链接(尤其参考式多次引用同一定义)需自行去重,AST 方式更容易拿到原始位置信息做 dedup
真正麻烦的是混合内容:一个 Markdown 片段里既有行内链接、又有自动链接、还有带 title 的扩展语法([text](url "title")),正则很难全覆盖,这时候 AST 不是“更高级的选择”,而是必要路径。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











