前言
又是好久沒寫部落格了
其實也不是沒寫,是最近在「做一個部落格」,從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,接下來應該會開始更新部落格開發筆記系列文章~(*^▽^*)
參考資料
- CommonMark.NET Wiki:https://github.com/Knagis/CommonMark.NET/wiki
- Markdig專案主頁:https://github.com/xoofx/markdig
- 相關issues:https://github.com/xoofx/markdig/issues/599
- 相關原始碼:https://github.com/xoofx/markdig/blob/master/src/Markdig/Renderers/Normalize/NormalizeRenderer.cs
- 微軟文件:https://docs.microsoft.com/en-us/windows/communitytoolkit/parsers/markdownparser
- https://www.songshizhao.com/blog/blogPage/1044.html