博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
为CommonMark.Net增加Table解析
阅读量:5972 次
发布时间:2019-06-19

本文共 3495 字,大约阅读时间需要 11 分钟。

最近发现markdown真的好方便,所以一直都在为知客户端上写总结(富文本编辑器虽然功能强大,但总是把文章弄得乱糟糟的)。

接下来就打算为自己的博客加上markdown解析的功能,然而.net平台下并没有特别合适的类库,一些前端框架倒是可以用,但是想要二次加工就不是很方便了(比如想生成一个带锚点的目录)。最后看到博客园官博提到CommonMark.NET,这个是一个markdown的标准解析引擎,但对于标准外的语法没有支持(比如Table),So,我们自己来加吧....

PS:实现的还是有些粗糙,照源码的思路似乎应该为Table在Block层面上解析,而这里直接使用Inline的方式(就是碰到竖线就认为是Table开始了,而Block应该对整个代码块进行判断,是否是一个Table),但姑且这样用了,有时间再完善。

源码逻辑

先来了解下现有的解析逻辑:

public static void Convert(TextReader source, TextWriter target, CommonMarkSettings settings = null){    if (settings == null)        settings = CommonMarkSettings.Default;     var document = ProcessStage1(source, settings);    ProcessStage2(document, settings);    ProcessStage3(document, target, settings);}

处理分为3个阶段

  1. markdown -> blocks
    按markdown语法创建代码块(比如标题、段落、列表、代码块、引用等),并组成一个树形结构,每个节点有FirstChild和NextSibling的索引,代码中的document是根节点。
  2. blocks -> inlines
    每个block中的内容按字符处理,碰到特殊符号(比如#,*,\n)就将符号及跟随的一段内容解析成相应的inline对象(标题,粗体、(软)换行),并用stack的方式实现标签的闭合。
    Inline对象也组成一个树形结构,有FirstChild和NextSibling的索引(但似乎只用到了NextSibling?)
  3. blocks/inlines -> html
    遍历所有Block中的Inline对象,输出相应的html代码

Table解析实现

Block解析部分比较复杂,这里采用Inline解析时把第一个竖线到最后一个竖线封装一个Table类型的Inline(人为控制一个Block只有一个Table吧),再实现Table类型的渲染方法即可。

为Inline增加一个类型Table:

public enum InlineTag : byte{    String = 0,    SoftBreak,    LineBreak,    Code,    RawHtml,    Emphasis,    Strong,    Link,    Image,    Strikethrough,    Table    //新增的Table类型}

为‘|’符号增加处理方法:

internal static Func
[] InitializeParsers(CommonMarkSettings settings){ var strikethroughTilde = 0 != (settings.AdditionalFeatures & CommonMarkAdditionalFeatures.StrikethroughTilde); var p = new Func
[strikethroughTilde ? 127 : 125]; p['\n'] = handle_newline; p['`'] = handle_backticks; p['\\'] = handle_backslash; p['&'] = HandleEntity; p['<'] = handle_pointy_brace; p['_'] = HandleEmphasis; p['*'] = HandleEmphasis; p['['] = HandleLeftSquareBracket; p[']'] = HandleRightSquareBracket; p['!'] = HandleExclamation; p['|'] = HandleTable; //增加'|'的解析方法,把|到|封装为一个Table类型的Inline if (strikethroughTilde) p['~'] = HandleTilde; return p;}private static Inline HandleTable(Subject subj){ //这里偷懒了,可以加个校验,确定是个table,否则单个'|'也会被解析 var start = subj.Buffer.IndexOf('|'); var last = subj.Buffer.LastIndexOf('|'); var inlTab = new Inline(InlineTag.Table, subj.Buffer.Substring(start, last - start + 1)); subj.Position = last + 1; return inlTab;}

Table类型Inline的渲染,InlinesToHtml:

switch (inline.Tag){    case InlineTag.Table:        //tab        writer.WriteConstant("
"); var lines = inline.LiteralContentValue.ToString().Split(new char[] { '\n' }, System.StringSplitOptions.RemoveEmptyEntries); int i = 0; foreach (var line in lines) { i++; if (line.Split(new char[] { '|', '-', ' ', '\n' }, System.StringSplitOptions.RemoveEmptyEntries).Length == 0) { continue; } writer.WriteConstant("
"); var tds = line.Split(new char[] { '|' }); for (int j = 1; j < tds.Length - 1; j++) { writer.WriteConstant(i == 1 ? "
"); } writer.WriteConstant("
" : " "); writer.WriteConstant(tds[j]); writer.WriteConstant(i == 1 ? "" : ""); } writer.WriteConstant("
"); break; ....... ......}

附上源码和dll:

ok,可以愉快的把md的笔记都粘来了~

参考文献:

转载于:https://www.cnblogs.com/ace-lj/p/5363001.html

你可能感兴趣的文章
连云港移动大数据服务水晶城
查看>>
D1net阅闻:亚马逊引入Biba的员工和专利,据称计划推出新的视频聊天服务
查看>>
智能安防系统市场调查
查看>>
2020年中国数据产业将占全球20% 成为数据中心
查看>>
法国葡萄酒商使用NFC技术,鉴定产品真伪
查看>>
A股公司拟16亿元买索尼一广州生产基地
查看>>
日媒:鸿海计划收购后统一运营夏普液晶业务
查看>>
SoapUI压力测试的指标项说明
查看>>
《深入理解Elasticsearch(原书第2版)》——1.2 何为Elasticsearch
查看>>
大数据理论遇上新兴分析工具 挑战无处不在
查看>>
预算有限,如何找到高性价比的供应商?
查看>>
三星电子表示:正加速中国本土化进程
查看>>
D1net阅闻:阿里为未来20年建独立研发部门 代号“NASA”
查看>>
物联网市场发展飞速 连网照明有望成香饽饽
查看>>
如何在物联网应用开发期间避免常见的安全性误区
查看>>
HttpAsyncClient 4.1-beta1 发布
查看>>
英特尔的 Linux 发行版提供了最快的开箱即用性能
查看>>
《Python程序设计》——2.3 输出
查看>>
《SolidWorks 2013中文版机械设计从入门到精通》一1.2 SolidWorks的文件操作
查看>>
《LabVIEW 虚拟仪器程序设计从入门到精通(第二版)》一第2章 LabVIEW前面板设计...
查看>>