首页 > 其他分享 >Markdown标题自动添加编号

Markdown标题自动添加编号

时间:2023-05-24 12:55:19浏览次数:47  
标签:Markdown return string lines 标题 titles 编号 添加

markdown写文档很方便,但是有个困扰的地方,就是标题的编号问题。
写文档的时候,经常会在中间插入新的标题和内容,所以手动管理编号的话,如果新的标题插在前面,则要调整后面所有的编号。

如果在文档完成后再手动加上编号的话,不仅容易忘记,
而且有时候我们是在其他编辑器里编辑文档再导出markdown的,比如用语雀编写文档再导出markdown,这时每次修改文档再导出就要重新给导出的文档添加编号。
我用语雀比较多,常常因此而困扰。

所以,用golang简单写了个命令行工具,用来给markdown文档的标题添加编号。

1. 处理流程

处理过程很简单:

  1. 首先读取markdown文件的所有行
  2. 然后依次解析每一行
    1. 如果是标题行,添加编号
    2. 非标题行,略过
  3. 将添加了编号的内容重新写入markdown文件

2. 主要步骤

主要的步骤有三个:

2.1. 读取markdown文件

// 获取文件所有的行
func getAllLines(fp string) ([]string, error) {
    fi, err := os.Open(fp)
    if err != nil {
        return nil, err
    }
    defer fi.Close()

    br := bufio.NewReader(fi)
    lines := make([]string, 0)
    for {
        a, _, c := br.ReadLine()
        if c == io.EOF {
            break
        }
        lines = append(lines, string(a))
    }

    return lines, nil
}

返回的是文件所有行的数组。

2.2. 添加标题编号

// 添加标题编号,最多支持五级标题
func addTitle(lines []string) ([]string, []ChangedLine) {
	cLines := make([]ChangedLine, 0)
	titles := [5]int{0, 0, 0, 0, 0}

	for index, line := range lines {
		titleLevel := getTitleLevel(line)
		switch titleLevel {
		case 1:
			titles[0]++
			lines[index] = strings.Replace(line, "# ", fmt.Sprintf("# %d. ", titles[0]), 1)
			titles = [5]int{titles[0], 0, 0, 0, 0}
		case 2:
			titles[1]++
			lines[index] = strings.Replace(line, "## ", fmt.Sprintf("## %d.%d. ", titles[0], titles[1]), 1)
			titles = [5]int{titles[0], titles[1], 0, 0, 0}
		case 3:
			titles[2]++
			lines[index] = strings.Replace(line, "### ", fmt.Sprintf("### %d.%d.%d. ", titles[0], titles[1], titles[2]), 1)
			titles = [5]int{titles[0], titles[1], titles[2], 0, 0}
		case 4:
			titles[3]++
			lines[index] = strings.Replace(line, "#### ", fmt.Sprintf("#### %d.%d.%d.%d. ", titles[0], titles[1], titles[2], titles[3]), 1)
			titles = [5]int{titles[0], titles[1], titles[2], titles[3], 0}
		case 5:
			titles[4]++
			lines[index] = strings.Replace(line, "##### ", fmt.Sprintf("##### %d.%d.%d.%d.%d. ", titles[0], titles[1], titles[2], titles[3], titles[4]), 1)
			titles = [5]int{titles[0], titles[1], titles[2], titles[3], titles[4]}
		}

		if titleLevel != -1 {
			cLines = append(cLines, ChangedLine{LineNo: index + 1, Before: line, After: lines[index]})
		}
	}

	return lines, cLines
}

这里支持最多5级标题的编号,写的略显繁琐,本身逻辑比较简单,暂时没有去优化。

获取标题的等级写了简单的小函数:
(根据markdown的语法,根据每行开头 # 的个数来判断是几级的标题)

// 获取标题的等级
func getTitleLevel(s string) int {
	if strings.HasPrefix(s, "# ") {
		return 1
	}
	if strings.HasPrefix(s, "## ") {
		return 2
	}
	if strings.HasPrefix(s, "### ") {
		return 3
	}
	if strings.HasPrefix(s, "#### ") {
		return 4
	}
	if strings.HasPrefix(s, "##### ") {
		return 5
	}

	return -1
}

2.3. 新内容写入markdown文件

// 写入多行数据
func writeLines(fp string, lines []string) error {
	content := strings.Join(lines, "\n")
	return ioutil.WriteFile(fp, []byte(content), 0644)
}

2.4. 步骤合并起来

此命令行工具使用了 cobra 框架,最后把修改的部分也打印出来了。

type ChangedLine struct {
	LineNo int
	Before string
	After  string
}

var rootCmd = &cobra.Command{
	Use:   "mt",
	Short: "给mkdown标题添加编号",
	RunE: func(cmd *cobra.Command, args []string) error {
		if len(args) < 1 {
			return fmt.Errorf("NO file input!")
		}
		fp := args[0]
		lines, err := getAllLines(fp)
		if err != nil {
			return err
		}

		newLines, changedLines := addTitle(lines)
		err = writeLines(fp, newLines)
		if err != nil {
			return err
		}

		fmt.Println("修改的内容:>>>")
		for _, cl := range changedLines {
			fmt.Println("===================================")
			fmt.Printf("line【%d】:\n修改前:%s\n修改后:%s\n", cl.LineNo, cl.Before, cl.After)
			fmt.Println("===================================")
		}

		return nil
	},
}

3. 使用方法

go build  # 编译后生成 mdtitle 二进制文件
./mdtitle xxxx.md   # 运行

本文最后附加的下载地址中有完整源码。
其中也包含编译好的二进制(linux和windows版本2个都有)。

4. 补充说明

今天一时起意写的小工具,只是为了方便给自己从语雀导出的markdown加标题编号。
一定还有很多不足之处有待完善,写完之后我自己感觉至少还需要完善:

  1. 没有判断文档是否已经有标题编号,已经有标题编号的情况,应当忽略继续添加标题编号
  2. 标题的层级是硬编码的,目前只支持5级标题(不过5级应该满足大部分情况了)

代码下载地址(其中包含编译好的linux和windows下的二进制):
md-title.zip: https://url11.ctfile.com/f/45455611-859852761-9f5f8e?p=6872
(访问密码: 6872)

标签:Markdown,return,string,lines,标题,titles,编号,添加
From: https://www.cnblogs.com/wang_yb/p/17427971.html

相关文章

  • 如何给布局或者控件添加边框
    如何给布局或者控件添加边框我在学习和开发JavaFX程序时,对Pane会有一些疑问,比如:它们的大小是怎样的?它们的大小和父节点或者窗口的关系是怎样的?相同的问题在控件上也存在,比如一个Label到底占据了多大的空间(因为默认Label没有边框展示)?我想,如果可以给布局或者控件添加......
  • centos 6上 yum检查epel源是否添加成功报错 Cannot retrieve metalink for repository
    在我们使用yum安装时,经常发现没有第三方源,此时需要安装epel(ExtraPackagesforEnterpriseLinux,企业版Linux的额外软件包)Epel是什么?它是Fedora小组维护的一个软件仓库项目,为RHEL/CentOS提供他们默认不提供的软件包。这个源兼容RHEL及像CentOS和ScientificLinux这样的衍生版本......
  • uniapp 数组添加不重复元素
    if(this.checkTimes.includes(_item.time)){this.checkTimes=this.checkTimes.filter((item)=>{returnitem!=_item.time;});}else{this.ch......
  • MarkDown的使用(一)
    前言刚刚步入工作,准备写博客来记录一下工作学习中遇到的困难,发现Markdown作为一款轻量级的文本标注语言编写博客较为轻松,故写下本篇记录Markdown语法的学习过程。初次写博客,若本文有什么不足之处,还请大家提出宝贵的意见。1文字的效果正常文字**加粗文字**加粗文字*文字倾......
  • 3d打印机添加AI炒面检测服务 klipper+fluidd ubuntu本地部署TheSpaghttiDetective Ser
    炒面检测(TheSpaghettiDetective)介绍:炒面检测服务可以借助打印机的摄像头,检测打印是否炒面(打印失败)并作出提醒或停止打印的一种服务,该服务由服务器和客户端组成客户端支持两种: ocoprint或klipper服务器也有两种:ocobi官方提供的有限免费服务......
  • markdown编辑器使用
    1.标题使用#号可表示1-6级标题,一级标题对应一个#号,二级标题对应两个#号,以此类推#一级标题##二级标题###三级标题####四级标题#####五级标题######六级标题2.字体**这是加粗的文字***这是倾斜的文字*`***这是斜体加粗的文字***~~这是加删除线的文字~~......
  • 为什么不能向下兼容呢?这是因为不同版本的 Refs 文件系统之间可能存在较大的差异,如接口
    Refs文件系统是在WindowsServer2012R2引入的,目前主要用于Windows服务器操作系统中。截至目前为止,Windows服务器操作系统中已经支持了三个版本的Refs文件系统:RefsV1:WindowsServer2012R2中引入的第一代Refs版本,该版本引入了Refs文件系统,并支持自动修复、数据......
  • Qt 的Cmake方式如何创建资源文件和添加类
    CLion(误,QTCreator)添加资源文件时选择Qt然后选择QtResourceFile单击choose,然后给你的资源文件输入一个名字比如res单击下一步,然后完成,保存这时候工程和上面添加类是一样的,看不到添加的资源文件,还是要手动到CMakeList.txt文件在里面手动输入res.qrc然后单击X关掉CMakeList......
  • Markdown基本语法
    Markdown学习标题 标题:#+标题名字几级标题几级对应#,记得空格字体粗体xx斜体x斜体加粗x划线xx引用xxxxxx分割线图片 超链接cctv列表表格            代码xxxx ......
  • 信号量和互斥锁详解 非MarkDown版
    [参考链接1](http://blog.chinaunix.net/uid-24612247-id-2305050.html)详细说明:```信号量强调的是线程(或进程)间的同步:“信号量用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别的线程,别的线程再进行某些动作(大家都在sem_wait的时候......