文章目录
- 工具功能亮点
- 1.核心实现解析
- 1. 剪贴板交互
- 2. HTML检测与提取
- 3. 转换规则设计
- 2. 完整代码
在日常工作中,我们经常遇到需要将网页表格快速转换为Markdown格式的场景。无论是文档编写、知识整理还是数据迁移,手动转换既耗时又容易出错。本文将介绍一个基于Go语言开发的轻量级工具,它能自动从剪贴板提取HTML表格并转换为Markdown格式。
工具功能亮点
- 一键转换:直接读取剪贴板中的HTML内容
- 智能识别:自动检测并提取首个HTML表格
- 格式优化:保留表格结构并添加Markdown语法
- 无缝衔接:结果自动写回剪贴板
1.核心实现解析
1. 剪贴板交互
// 读取剪贴板内容
content, err := clipboard.ReadAll()
// 将结果写回剪贴板
err = clipboard.WriteAll(markdown)
使用atotto/clipboard
库实现跨平台剪贴板操作,无需文件中间步骤。
2. HTML检测与提取
func isHTML(s string) bool {
return strings.Contains(s, "<table") ||
strings.Contains(s, "<tr")
}
func extractFirstTable(html string) string {
start := strings.Index(html, "<table")
end := strings.Index(html[start:], "</table>")
return html[start:start+end+8] // 截取完整table标签
}
通过简单高效的字符串扫描定位表格位置,避免复杂解析。
3. 转换规则设计
converter.AddRules(md.Rule{
Filter: []string{"table", "tr", "td", "th"},
Replacement: func(content string, selec *goquery.Selection) *string {
if selec.Is("tr") {
return md.String("|" + content + "|\n")
}
if selec.Is("td") {
return md.String(strings.TrimSpace(content) + "|")
}
// 其他元素处理...
}
})
关键转换逻辑:
tr
转换为行:|内容|
td/th
转换为单元格:内容|
- 自动添加表头分隔线:
|---|---|
2. 完整代码
package main
import (
"fmt"
"log"
"os"
"strings"
md "github.com/JohannesKaufmann/html-to-markdown"
"github.com/PuerkitoBio/goquery"
"github.com/atotto/clipboard"
)
func main() {
// 读取剪贴板内容
content, err := clipboard.ReadAll()
if err != nil {
log.Fatal("读取剪贴板失败:", err)
}
// 检查是否为HTML内容
if !isHTML(content) {
fmt.Println("剪贴板内容不是HTML格式")
os.Exit(0)
}
// 提取第一个表格
tableHTML, err := extractFirstTable(content)
if err != nil {
log.Fatal("提取表格失败:", err)
}
if tableHTML == "" {
fmt.Println("未找到HTML表格")
os.Exit(0)
}
// 转换为Markdown
converter := md.NewConverter("", true, nil)
// 添加表格转换规则
converter.AddRules(
md.Rule{
Filter: []string{"table", "tr", "td", "th"},
Replacement: func(content string, selec *goquery.Selection, opt *md.Options) *string {
if selec.Is("table") {
// 添加表头分隔线
rows := strings.Split(strings.TrimSpace(content), "\n")
if len(rows) > 1 {
header := rows[0]
cols := strings.Count(header, "|") - 1
separator := "|" + strings.Repeat("---|", cols)
// 合并所有行,确保每行数据单独显示
content = strings.Join(append([]string{header, separator}, rows[1:]...), "\n") + "\n"
}
return &content
}
if selec.Is("tr") {
content = "|" + strings.TrimRight(content, "|") + "|\n"
return &content
}
if selec.Is("th") || selec.Is("td") {
content = strings.ReplaceAll(content, "\n", "<br>")
content = strings.TrimSpace(content) + "|"
return &content
}
return nil
},
},
)
markdown, err := converter.ConvertString(tableHTML)
if err != nil {
log.Fatal("转换Markdown失败:", err)
}
// 输出结果到控制台
fmt.Println("转换后的Markdown表格:")
fmt.Println(markdown)
// 将结果写入剪贴板
err = clipboard.WriteAll(markdown)
if err != nil {
log.Fatal("写入剪贴板失败:", err)
}
fmt.Println("已成功将Markdown表格写入剪贴板")
}
// isHTML 检查字符串是否是HTML格式
func isHTML(s string) bool {
return strings.Contains(strings.ToLower(s), "<html") ||
strings.Contains(strings.ToLower(s), "<table") ||
strings.Contains(strings.ToLower(s), "<tr") ||
strings.Contains(strings.ToLower(s), "<td")
}
// extractFirstTable 从HTML中提取第一个表格
func extractFirstTable(html string) (string, error) {
// 简单的提取逻辑,实际应用中可能需要更复杂的HTML解析
start := strings.Index(strings.ToLower(html), "<table")
if start == -1 {
return "", nil
}
end := strings.Index(strings.ToLower(html[start:]), "</table>")
if end == -1 {
return "", nil
}
return html[start : start+end+8], nil // +8 是 </table> 的长度
}