在日常工作中,我们经常遇到需要将网页表格快速转换为Markdown格式的场景。无论是文档编写、知识整理还是数据迁移,手动转换既耗时又容易出错。本文将介绍一个基于Go语言开发的轻量级工具,它能自动从剪贴板提取HTML表格并转换为Markdown格式。


工具功能亮点
  1. 一键转换:直接读取剪贴板中的HTML内容
  2. 智能识别:自动检测并提取首个HTML表格
  3. 格式优化:保留表格结构并添加Markdown语法
  4. 无缝衔接:结果自动写回剪贴板

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> 的长度
}

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐