• 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,接下来应该会开始更新博客开发笔记系列文章~(*^▽^*)

    参考资料


    __EOF__

  • 本文作者: 程序设计实验室
  • 本文链接: https://www.cnblogs.com/deali/p/16027455.html
  • 关于博主: 公众号:程序设计实验室,欢迎交流~
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • 相关阅读:
    动作捕捉系统用于下肢外骨骼开发
    SSD【目标检测篇】
    安卓和ios设置自己的短链
    【记录】PyCharm 安装 preprocess 模块(库)|| 在 PyCharm 中安装 preprocess 失败,故而在 终端 安装
    项目管理软件dhtmlxGantt配置教程(九):输入值验证方法
    『Linux升级路』基本指令
    STM32 float浮点数转换成四个字节
    【7. 进程管理】
    Go 字符串类型的实现原理
    JVM 垃圾回收机制(可达性分析、引用计数)
  • 原文地址:https://www.cnblogs.com/deali/p/16027455.html