ToB企服应用市场:ToB评测及商务社交产业平台

标题: Markdown标题自动添加编号 [打印本页]

作者: 忿忿的泥巴坨    时间: 2023-5-24 14:04
标题: Markdown标题自动添加编号
用markdown写文档很方便,但是有个困扰的地方,就是标题的编号问题。
写文档的时候,经常会在中间插入新的标题和内容,所以手动管理编号的话,如果新的标题插在前面,则要调整后面所有的编号。
如果在文档完成后再手动加上编号的话,不仅容易忘记,
而且有时候我们是在其他编辑器里编辑文档再导出markdown的,比如用语雀编写文档再导出markdown,这时每次修改文档再导出就要重新给导出的文档添加编号。
我用语雀比较多,常常因此而困扰。
所以,用golang简单写了个命令行工具,用来给markdown文档的标题添加编号。
1. 处理流程

处理过程很简单:
2. 主要步骤

主要的步骤有三个:
2.1. 读取markdown文件
  1. // 获取文件所有的行
  2. func getAllLines(fp string) ([]string, error) {
  3.     fi, err := os.Open(fp)
  4.     if err != nil {
  5.         return nil, err
  6.     }
  7.     defer fi.Close()
  8.     br := bufio.NewReader(fi)
  9.     lines := make([]string, 0)
  10.     for {
  11.         a, _, c := br.ReadLine()
  12.         if c == io.EOF {
  13.             break
  14.         }
  15.         lines = append(lines, string(a))
  16.     }
  17.     return lines, nil
  18. }
复制代码
返回的是文件所有行的数组。
2.2. 添加标题编号
  1. // 添加标题编号,最多支持五级标题
  2. func addTitle(lines []string) ([]string, []ChangedLine) {
  3.         cLines := make([]ChangedLine, 0)
  4.         titles := [5]int{0, 0, 0, 0, 0}
  5.         for index, line := range lines {
  6.                 titleLevel := getTitleLevel(line)
  7.                 switch titleLevel {
  8.                 case 1:
  9.                         titles[0]++
  10.                         lines[index] = strings.Replace(line, "# ", fmt.Sprintf("# %d. ", titles[0]), 1)
  11.                         titles = [5]int{titles[0], 0, 0, 0, 0}
  12.                 case 2:
  13.                         titles[1]++
  14.                         lines[index] = strings.Replace(line, "## ", fmt.Sprintf("## %d.%d. ", titles[0], titles[1]), 1)
  15.                         titles = [5]int{titles[0], titles[1], 0, 0, 0}
  16.                 case 3:
  17.                         titles[2]++
  18.                         lines[index] = strings.Replace(line, "### ", fmt.Sprintf("### %d.%d.%d. ", titles[0], titles[1], titles[2]), 1)
  19.                         titles = [5]int{titles[0], titles[1], titles[2], 0, 0}
  20.                 case 4:
  21.                         titles[3]++
  22.                         lines[index] = strings.Replace(line, "#### ", fmt.Sprintf("#### %d.%d.%d.%d. ", titles[0], titles[1], titles[2], titles[3]), 1)
  23.                         titles = [5]int{titles[0], titles[1], titles[2], titles[3], 0}
  24.                 case 5:
  25.                         titles[4]++
  26.                         lines[index] = strings.Replace(line, "##### ", fmt.Sprintf("##### %d.%d.%d.%d.%d. ", titles[0], titles[1], titles[2], titles[3], titles[4]), 1)
  27.                         titles = [5]int{titles[0], titles[1], titles[2], titles[3], titles[4]}
  28.                 }
  29.                 if titleLevel != -1 {
  30.                         cLines = append(cLines, ChangedLine{LineNo: index + 1, Before: line, After: lines[index]})
  31.                 }
  32.         }
  33.         return lines, cLines
  34. }
复制代码
这里支持最多5级标题的编号,写的略显繁琐,本身逻辑比较简单,暂时没有去优化。
获取标题的等级写了简单的小函数:
(根据markdown的语法,根据每行开头 # 的个数来判断是几级的标题)
  1. // 获取标题的等级
  2. func getTitleLevel(s string) int {
  3.         if strings.HasPrefix(s, "# ") {
  4.                 return 1
  5.         }
  6.         if strings.HasPrefix(s, "## ") {
  7.                 return 2
  8.         }
  9.         if strings.HasPrefix(s, "### ") {
  10.                 return 3
  11.         }
  12.         if strings.HasPrefix(s, "#### ") {
  13.                 return 4
  14.         }
  15.         if strings.HasPrefix(s, "##### ") {
  16.                 return 5
  17.         }
  18.         return -1
  19. }
复制代码
2.3. 新内容写入markdown文件
  1. // 写入多行数据
  2. func writeLines(fp string, lines []string) error {
  3.         content := strings.Join(lines, "\n")
  4.         return ioutil.WriteFile(fp, []byte(content), 0644)
  5. }
复制代码
2.4. 步骤合并起来

此命令行工具使用了 cobra 框架,最后把修改的部分也打印出来了。
  1. type ChangedLine struct {
  2.         LineNo int
  3.         Before string
  4.         After  string
  5. }
  6. var rootCmd = &cobra.Command{
  7.         Use:   "mt",
  8.         Short: "给mkdown标题添加编号",
  9.         RunE: func(cmd *cobra.Command, args []string) error {
  10.                 if len(args) < 1 {
  11.                         return fmt.Errorf("NO file input!")
  12.                 }
  13.                 fp := args[0]
  14.                 lines, err := getAllLines(fp)
  15.                 if err != nil {
  16.                         return err
  17.                 }
  18.                 newLines, changedLines := addTitle(lines)
  19.                 err = writeLines(fp, newLines)
  20.                 if err != nil {
  21.                         return err
  22.                 }
  23.                 fmt.Println("修改的内容:>>>")
  24.                 for _, cl := range changedLines {
  25.                         fmt.Println("===================================")
  26.                         fmt.Printf("line【%d】:\n修改前:%s\n修改后:%s\n", cl.LineNo, cl.Before, cl.After)
  27.                         fmt.Println("===================================")
  28.                 }
  29.                 return nil
  30.         },
  31. }
复制代码
3. 使用方法
  1. go build  # 编译后生成 mdtitle 二进制文件
  2. ./mdtitle xxxx.md   # 运行
复制代码
本文最后附加的下载地址中有完整源码。
其中也包含编译好的二进制(linux和windows版本2个都有)。
4. 补充说明

今天一时起意写的小工具,只是为了方便给自己从语雀导出的markdown加标题编号。
一定还有很多不足之处有待完善,写完之后我自己感觉至少还需要完善:
代码下载地址(其中包含编译好的linux和windows下的二进制):
md-title.zip:  https://url11.ctfile.com/f/45455611-859852761-9f5f8e?p=6872
(访问密码: 6872)

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4