C#解析Markdown文檔,實現替換圖片鏈接操作


前言

又是好久沒寫博客了

其實也不是沒寫,是最近在「做一個博客」,從2月21日開始,大概一個多星期的時間,瘋狂刷進度,邊寫代碼邊寫了一整系列的博客開發筆記,目前為止已經寫了16篇了,然后上3月之后工作有點忙加上有點沉迷原神,然后進度就暫時慢下來了

事實證明做什么事情一旦停下來就會產生惰性,於是停了這么久,我終於下定決心繼續更新!

這次開發的博客用的是C#語言,搭配.netcore技術棧;前端繼續用我比較熟悉的Bootstrap做布局,然后稍微折騰一下;管理端用的是Vue…… 過程中總能遇到一些技術問題,除了在博客開發筆記系列里記錄,還是把一些普適性的解決方案單獨拿出來。

我的博客采用程序員最愛的Markdown語法書寫,而眾所周知markdown有一個缺點就是關聯圖片資源麻煩

因為我的博客需要實現本地用Typora寫的Markdown文檔導入,所以解析markdown文檔並處理導入圖片資源是一個繞不過的坎。

如題,本文介紹的是C#解析Markdown文檔。

Markdig庫

之前我用Python實現過解析Markdown文檔,Python生態里相關的庫太多了,有很多很好的選擇,之前我寫的用Python實現解析Markdown的文章:python實現解析markdown文檔中的圖片,並且保存到本地~

然而C#這邊基本沒啥可選的,官方的Markdown庫也標記為棄用狀態,推薦遷移到Markdig這個庫……

所以就沒得選了,只能用這個Markdig。

官方介紹:

Markdig is a fast, powerful, CommonMark compliant, extensible Markdown processor for .NET.

其實這個庫也不難用,但注意官方介紹里有這么一句話:

NOTE: The repository is under construction. There will be a dedicated website and proper documentation at some point!

喵的!就是完全沒文檔,用法基本靠猜和啃源碼 ヽ(ー_ー)ノ

為了實現這個markdown圖片導入,我只能硬着頭皮搞起來

實現思路

Markdig有一個管道機制

舉個例子的偽代碼如下:

var pipeline = new MarkdownPipelineBuilder()
    .UseExt1()
    .UseExt2()
    .UseExt3()
    .Build();
var result = Markdown.ToHtml("This is a text with some *emphasis*", pipeline);

可以在解析Markdown過程中對Markdown文檔做一些修飾處理

一開始我想到自己寫一個管道來實現將Markdown里的圖片鏈接做替換處理

然而(可能因為太菜)看了好幾個官方的管道代碼,也沒琢磨出怎么實現我要的效果

直到我回想起官方介紹里的一個關鍵詞:CommonMark compliant,就是說這玩意是兼容CommonMark

靈光一閃,Markdig因為是新項目還沒文檔,那作為老項目的CommonMark總有文檔吧,於是我去找到了CommonMark.NET項目,一看果然有文檔,雖然兩者的API並不完全一致,但經過我的半蒙半猜的探索,終於是把要的功能搞定了~ ( ̄▽ ̄)~*

實現代碼

終於上代碼啦~

首先讀取一個Markdown文檔,得到MarkdownDocument對象

// 引入需要用到的命名空間
using Markdig;
using Markdig.Renderers.Normalize;
using Markdig.Syntax;
using Markdig.Syntax.Inlines;

var filepath = "temp/blog/機器學習/多個約束條件下的二維裝箱問題——尋找《開羅拉面店》最優布局.md";
var md = File.ReadAllText(filepath);
var document = Markdown.Parse(md);

這個文檔的部分內容如下:

## 前言
前段時間無聊回坑玩《開羅拉面店》,這是一款模擬經營類的小游戲,不管是畫風還是游戲性都很對我胃口。

![](多個約束條件下的二維裝箱問題——尋找《開羅拉面店》最優布局.assets/8869373-ea70bbc1e5c28b62.png)

![](多個約束條件下的二維裝箱問題——尋找《開羅拉面店》最優布局.assets/8869373-3dd13511e9063800.png)

![](多個約束條件下的二維裝箱問題——尋找《開羅拉面店》最優布局.assets/8869373-8fcc0475f92cfc84.png)

里面有一個玩法是拉面店布局,就給你一塊地,還有幾家店鋪,你可以隨便鋪隨便擺,當然肯定是擺的越多家店鋪越好。

![](多個約束條件下的二維裝箱問題——尋找《開羅拉面店》最優布局.assets/8869373-f2c6578cb8f77c31.png)

我一開始玩的時候也沒想那么多,隨便擺了擺就完事了,但玩到后期人氣上不去,我就突發奇想,能不能把所有店鋪擺進去?或者能不能盡可能多地去鋪滿這塊地?

Markdig會把Markdown文檔解析成一個文檔樹,接下來可以像DOM操作那樣遍歷文檔節點了~

下面的代碼是找出Markdown中的圖片鏈接節點,並給圖片鏈接加上前綴

foreach (var node in document.AsEnumerable()) {
    if (node is ParagraphBlock { Inline: { } } paragraphBlock) {
        foreach (var inline in paragraphBlock.Inline) {
            if (inline is LinkInline {IsImage: true} linkInline) {
                // 這里就是圖片鏈接了
                // 實現給圖片鏈接加上前綴
                linkInline.Url = $"http://127.0.0.1:5038/assets/blog/{linkInline.Url}";
                Console.WriteLine(linkInline.Url);
            }
        }
    }
}

然后把修改完的Markdown文檔重新輸出:

using (var writer = new StringWriter()) {
    var render = new NormalizeRenderer(writer);
    render.Render(document);
    Console.WriteLine(writer.ToString());
}

最終實現的效果就是這樣

## 前言

前段時間無聊回坑玩《開羅拉面店》,這是一款模擬經營類的小游戲,不管是畫風還是游戲性都很對我胃口。

![](http://127.0.0.1:5038/assets/blog/多個約束條件下的二維裝箱問題——尋找《開羅拉面店》最優布局.assets/8869373-ea70bbc1e5c28b62.png)

![](http://127.0.0.1:5038/assets/blog/多個約束條件下的二維裝箱問題——尋找《開羅拉面店》最優布局.assets/8869373-3dd13511e9063800.png)

![](http://127.0.0.1:5038/assets/blog/多個約束條件下的二維裝箱問題——尋找《開羅拉面店》最優布局.assets/8869373-8fcc0475f92cfc84.png)

里面有一個玩法是拉面店布局,就給你一塊地,還有幾家店鋪,你可以隨便鋪隨便擺,當然肯定是擺的越多家店鋪越好。

后續

能實現把markdown文檔里的圖片鏈接拿出來,那后續的圖片導入、鏈接替換就好辦了,當然這是博客開發筆記里的內容,本文就不寫了。

C#語言很不錯,可惜第三方庫的生態還是差了點,這個問題如果我用Python的話早就解決了,但C#的話就只能折騰,我甚至一度想要自己造個輪子來解析了……

其實應該不難,我想到的辦法就是每一行遍歷文檔,然后用正則表達式把圖片鏈接匹配出來,后續處理完成再用正則做替換,不過不太優雅就是了,在這個寫代碼靠copy的時代還是要有點追求,不然跟咸魚有什么區別呢……

然后再嘮一下最近在搞的好玩的東西:

  • 受俄烏戰爭警醒的「去Windows化」
  • 尋找國內的微信替代品「去騰訊化」

OK,接下來應該會開始更新博客開發筆記系列文章~(*^▽^*)

參考資料


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM