Markdown標題自動添加編號

来源:https://www.cnblogs.com/wang_yb/archive/2023/05/24/17427971.html
-Advertisement-
Play Games

用`markdown`寫文檔很方便,但是有個困擾的地方,就是標題的編號問題。 寫文檔的時候,經常會在中間插入新的標題和內容,所以手動管理編號的話,如果新的標題插在前面,則要調整後面所有的編號。 如果在文檔完成後再手動加上編號的話,不僅容易忘記, 而且有時候我們是在其他編輯器里編輯文檔再導出`mark ...


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)


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 摘要:這篇文章將詳細講解圖像形態學知識,主要介紹圖像腐蝕處理和膨脹處理。 本文分享自華為雲社區《[Python從零到壹] 四十七.圖像增強及運算篇之腐蝕和膨脹詳解》,作者: eastmount 。 一.形態學理論知識 數學形態學的應用可以簡化圖像數據,保持它們基本的形狀特征,並出去不相干的結構。數學 ...
  • 親測好使的安裝方式親測好使的安裝方式親測好使的安裝方式親測好使的安裝方式親測好使的安裝方式親測好使的安裝方式親測好使的安裝方式親測好使的安裝方式親測好使的安裝方式親測好使的安裝方式親測好使的安裝方式親測好使的安裝方式親測好使的安裝方式親測好使的安裝方式親測好使的安裝方式親測好使的安裝方式親測好使的安 ...
  • 我們在學習 Java 基礎時就知道可以生成隨機數,可以為我們枯燥的學習增加那麼一丟丟的樂趣。本文就來介紹 Java 隨機數。 ...
  • ## 教程簡介 Ruby,一種簡單快捷的面向對象(面向對象程式設計)腳本語言,在20世紀90年代由日本人松本行弘(Yukihiro Matsumoto)開發,遵守GPL協議和Ruby License。它的靈感與特性來自於 Perl、Smalltalk、Eiffel、Ada以及 Lisp 語言。由 R ...
  • # 一、Java配置線程池 ## 1、線程池==分類==、其他 ### 1.1、分類 ==IO密集型 和 CPU密集型== 任務的特點不同,因此針對不同類型的任務,選擇不同類型的線程池可以獲得更好的性能表現。 #### 1.1. IO密集型任務 ​ IO密集型任務的特點是需要頻繁讀寫磁碟、網路或者其 ...
  • 一、準備一下 開發環境 Pycharm python 3.8 ffmpeg 模塊的使用 requests re subprocess 二、基本思路流程 1、明確需求 採集下破站視頻數據通過開發者工具進行抓包分析,分析破站視頻數據的來源。 開發者工具的使用 打開方式: 滑鼠右鍵點擊檢查選擇Networ ...
  • ## 前言 如題,這個小玩意,就是不限制你查的是哪張表,用的是什麼類。 我直接一把梭,嘎嘎給你一頓導出。 我知道,這是很多人都想過的, 至少我就收到很多人問過我這個類似的問題。 我也跟他們說了,但是他們就是不動手,其實真的很簡單。 不動手怎麼辦? 我出手唄。 不多說開搞 。 ## 正文 玩法很簡單。 ...
  • # 超輕量級 DynamicTableNameInnerInterceptor是mybatis-plug的一個攔截器插件,可以自己定義需要攔截的表單,然後對它進行加工,這時mybatis-plus就會把SQL代碼的表名加上你的這個裝飾。 # 封裝的思想 我們通常把mybatis做成一個包,公司其它同 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 微服務架構已經成為搭建高效、可擴展系統的關鍵技術之一,然而,現有許多微服務框架往往過於複雜,使得我們普通開發者難以快速上手並體驗到微服務帶了的便利。為瞭解決這一問題,於是作者精心打造了一款最接地氣的 .NET 微服務框架,幫助我們輕鬆構建和管理微服務應用。 本框架不僅支持 Consul 服務註 ...
  • 先看一下效果吧: 如果不會寫動畫或者懶得寫動畫,就直接交給Blend來做吧; 其實Blend操作起來很簡單,有點類似於在操作PS,我們只需要設置關鍵幀,滑鼠點來點去就可以了,Blend會自動幫我們生成我們想要的動畫效果. 第一步:要創建一個空的WPF項目 第二步:右鍵我們的項目,在最下方有一個,在B ...
  • Prism:框架介紹與安裝 什麼是Prism? Prism是一個用於在 WPF、Xamarin Form、Uno 平臺和 WinUI 中構建鬆散耦合、可維護和可測試的 XAML 應用程式框架 Github https://github.com/PrismLibrary/Prism NuGet htt ...
  • 在WPF中,屏幕上的所有內容,都是通過畫筆(Brush)畫上去的。如按鈕的背景色,邊框,文本框的前景和形狀填充。藉助畫筆,可以繪製頁面上的所有UI對象。不同畫筆具有不同類型的輸出( 如:某些畫筆使用純色繪製區域,其他畫筆使用漸變、圖案、圖像或繪圖)。 ...
  • 前言 嗨,大家好!推薦一個基於 .NET 8 的高併發微服務電商系統,涵蓋了商品、訂單、會員、服務、財務等50多種實用功能。 項目不僅使用了 .NET 8 的最新特性,還集成了AutoFac、DotLiquid、HangFire、Nlog、Jwt、LayUIAdmin、SqlSugar、MySQL、 ...
  • 本文主要介紹攝像頭(相機)如何採集數據,用於類似攝像頭本地顯示軟體,以及流媒體數據傳輸場景如傳屏、視訊會議等。 攝像頭採集有多種方案,如AForge.NET、WPFMediaKit、OpenCvSharp、EmguCv、DirectShow.NET、MediaCaptre(UWP),網上一些文章以及 ...
  • 前言 Seal-Report 是一款.NET 開源報表工具,擁有 1.4K Star。它提供了一個完整的框架,使用 C# 編寫,最新的版本採用的是 .NET 8.0 。 它能夠高效地從各種資料庫或 NoSQL 數據源生成日常報表,並支持執行複雜的報表任務。 其簡單易用的安裝過程和直觀的設計界面,我們 ...
  • 背景需求: 系統需要對接到XXX官方的API,但因此官方對接以及管理都十分嚴格。而本人部門的系統中包含諸多子系統,系統間為了穩定,程式間多數固定Token+特殊驗證進行調用,且後期還要提供給其他兄弟部門系統共同調用。 原則上:每套系統都必須單獨接入到官方,但官方的接入複雜,還要官方指定機構認證的證書 ...
  • 本文介紹下電腦設備關機的情況下如何通過網路喚醒設備,之前電源S狀態 電腦Power電源狀態- 唐宋元明清2188 - 博客園 (cnblogs.com) 有介紹過遠程喚醒設備,後面這倆天瞭解多了點所以單獨加個隨筆 設備關機的情況下,使用網路喚醒的前提條件: 1. 被喚醒設備需要支持這WakeOnL ...
  • 前言 大家好,推薦一個.NET 8.0 為核心,結合前端 Vue 框架,實現了前後端完全分離的設計理念。它不僅提供了強大的基礎功能支持,如許可權管理、代碼生成器等,還通過採用主流技術和最佳實踐,顯著降低了開發難度,加快了項目交付速度。 如果你需要一個高效的開發解決方案,本框架能幫助大家輕鬆應對挑戰,實 ...