返回文章列表文章索引阅读全文
STARBLOG / 阅读手记
C#

Parsing Markdown Documents and Handling Image Links in C#

Preface It's been a long time since I last wrote a blog post It's not that I haven't been writing—I've been "building a blog" recently. Starting from February 21st, I spent about a week or so frantically pushing progress, writing code while also writing a whole series of blog development notes. So far I've written 16 of them. Then after March, work got a bit busy ~~plus I got a bit addicted to Genshin Impact~~, so progress slowed down for a while It's proven that once you stop doing something, inertia sets in. After pausing for so long, I've finally made up my mind to continue updating! The blog I'm developing this time uses the C# language, with the .NET Core tech stack; front

曦远 (DealiAxy)约 20 分钟
目录6 个章节

Preface

It's been a long time since I last wrote a blog post

It's not that I haven't been writing—I've been "building a blog" recently. Starting from February 21st, I spent about a week or so frantically pushing progress, writing code while also writing a whole series of blog development notes. So far I've written 16 of them. Then after March, work got a bit busy plus I got a bit addicted to Genshin Impact, so progress slowed down for a while

It's proven that once you stop doing something, inertia sets in. After pausing for so long, I've finally made up my mind to continue updating!

The blog I'm developing this time uses the C# language, with the .NET Core tech stack. For the frontend I'll continue using Bootstrap, which I'm fairly familiar with, for layout, with a bit of tinkering. The admin side uses Vue... Along the way I keep running into technical problems. Besides recording them in the blog development notes series, I'll also pull out some more generally applicable solutions separately.

My blog is written in Markdown, programmers' favorite syntax, and as everyone knows, one downside of markdown is that associating image resources is a hassle

Because my blog needs to support importing Markdown documents written locally in Typora, parsing markdown documents and handling imported image resources is a hurdle I can't avoid.

As the title says, this article is about parsing Markdown documents in C#.

The Markdig Library

I previously implemented Markdown document parsing in Python. There are tons of related libraries in the Python ecosystem, with many great options. Here's an article I wrote before about parsing Markdown in Python: Parsing images in a markdown document with Python and saving them locally~

However, on the C# side there's basically nothing to choose from. The official Markdown library is also marked as deprecated, and they recommend migrating to the Markdig library...

So there's no choice—I have to use this Markdig.

Official introduction:

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

This library isn't actually that hard to use, but notice this sentence in the official introduction:

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

Damn it! There's basically no documentation at all. Usage is pretty much all guessing and digging through the source code ヽ(ー_ー)ノ

To implement this markdown image import, I had no choice but to grit my teeth and get on with it

Implementation Approach

Markdig has a pipeline mechanism

Here's some example pseudocode:

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

You can apply some modifications to the Markdown document during the parsing process

At first I thought of writing my own pipeline to replace the image links in the Markdown

However (maybe because I'm too noob) after looking at several official pipeline code samples, I still couldn't figure out how to achieve the effect I wanted

Until I recalled a key phrase from the official introduction: CommonMark compliant, meaning this thing is compatible with CommonMark

A flash of inspiration: since Markdig is a new project without documentation yet, the older CommonMark project should have docs, right? So I went and found the CommonMark.NET project, and sure enough it had documentation. Although the APIs of the two aren't completely identical, after some half-guessing, half-exploring, I finally got the functionality I needed working~ ( ̄▽ ̄)~*

Implementation Code

Finally, time for the code~

First, read a Markdown document to get a MarkdownDocument object

// 引入需要用到的命名空间
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);

Part of this document looks like this:

## 前言
前段时间无聊回坑玩《开罗拉面店》,这是一款模拟经营类的小游戏,不管是画风还是游戏性都很对我胃口。

![](多个约束条件下的二维装箱问题——寻找《开罗拉面店》最优布局.assets/8869373-ea70bbc1e5c28b62.png)

![](多个约束条件下的二维装箱问题——寻找《开罗拉面店》最优布局.assets/8869373-3dd13511e9063800.png)

![](多个约束条件下的二维装箱问题——寻找《开罗拉面店》最优布局.assets/8869373-8fcc0475f92cfc84.png)

里面有一个玩法是拉面店布局,就给你一块地,还有几家店铺,你可以随便铺随便摆,当然肯定是摆的越多家店铺越好。

![](多个约束条件下的二维装箱问题——寻找《开罗拉面店》最优布局.assets/8869373-f2c6578cb8f77c31.png)

我一开始玩的时候也没想那么多,随便摆了摆就完事了,但玩到后期人气上不去,我就突发奇想,能不能把所有店铺摆进去?或者能不能尽可能多地去铺满这块地?

Markdig parses the Markdown document into a document tree, and then you can traverse the document nodes just like DOM operations~

The following code finds image link nodes in the Markdown and adds a prefix to the image links

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);
            }
        }
    }
}

Then re-output the modified Markdown document:

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

The final result looks like this

## 前言

前段时间无聊回坑玩《开罗拉面店》,这是一款模拟经营类的小游戏,不管是画风还是游戏性都很对我胃口。

![](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)

里面有一个玩法是拉面店布局,就给你一块地,还有几家店铺,你可以随便铺随便摆,当然肯定是摆的越多家店铺越好。

Follow-up

Once you can extract the image links from a markdown document, the subsequent image import and link replacement become easy. Of course that's content for the blog development notes, so I won't cover it in this article.

C# is a great language, but unfortunately the third-party library ecosystem is still a bit lacking. If I were using Python, this problem would have been solved long ago, but with C# I just have to tinker. I even considered rolling my own parser at one point...

It shouldn't actually be that hard. The approach I thought of was to iterate through the document line by line, then use regex to match the image links, and after subsequent processing use regex again for replacement. It's just not very elegant, though. In this era of writing code by copying, you still need to have some standards, otherwise what's the difference between you and a salted fish...

Let me also chat a bit about some fun things I've been working on recently:

  • "De-Windows-ification" prompted by the Russia-Ukraine war
  • Looking for a domestic WeChat alternative: "De-Tencent-ification"

OK, next I should start updating the blog development notes series~(*^▽^*)

References

_EOF_

Parsing Markdown Documents and Handling Image Links in C#

本文作者:
程序设计实验室
版权声明:
本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

相关文章

C#学习(一)委托的概念和使用

前言 C#学习系列是根据我以前的笔记整理出来复习,顺便发一下文章做个记录。 先引用一个介绍: C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针。委托(Delegate) 是存有对某个方法的引用的一种引用类型变量。引用可在运行时被改变。 委托(Delegate)特别用于实现事件和回调方法。所有的委托(Delegate)都派生自 System.Delegate 类。 根据使用其他

2021-12-18 · C# · 约 1 分钟

在.NetCore(C#)中使用ODP-NET-Core+Dapper操作Oracle数据库

前言 虽然一直在说“去IOE化”,但是在国企和政府,Oracle的历史包袱实在太重了,甚至很多业务逻辑都是写在Oracle的各种存储过程里面实现的…… 我们的系统主要的技术栈是Django / Spring / AspNetCore,Java的不必说对Oracle支持肯定没问题,关键在于Django对Oracle版本有要求,兼容性不是特别好,Oracle版本没办法随意升级的,所以我想到用.Net

2021-12-18 · C# · 约 1 分钟

讨论

共 0 条

良言一句三冬暖,恶语伤人六月寒。

加载评论中…