zoukankan      html  css  js  c++  java
  • 为CommonMark.Net增加Table解析

    最近发现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中的内容按字符处理,碰到特殊符号(比如#,*, )就将符号及跟随的一段内容解析成相应的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<Subject, Inline>[] InitializeParsers(CommonMarkSettings settings)
    {
        var strikethroughTilde = 0 != (settings.AdditionalFeatures & CommonMarkAdditionalFeatures.StrikethroughTilde);
     
        var p = new Func<Subject, Inline>[strikethroughTilde ? 127 : 125];
        p['
    '] = 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("<table class="table table-bordered table-striped">");
            var lines = inline.LiteralContentValue.ToString().Split(new char[] { '
    ' }, System.StringSplitOptions.RemoveEmptyEntries);
            int i = 0;
            foreach (var line in lines)
            {
                i++;
     
                if (line.Split(new char[] { '|', '-', ' ', '
    ' }, System.StringSplitOptions.RemoveEmptyEntries).Length == 0)
                {
                    continue;
                }
     
                writer.WriteConstant("<tr>");
                var tds = line.Split(new char[] { '|' });
                for (int j = 1; j < tds.Length - 1; j++)
                {
                    writer.WriteConstant(i == 1 ? "<th>" : "<td>");
                    writer.WriteConstant(tds[j]);
                    writer.WriteConstant(i == 1 ? "</th>" : "</td>");
                }
                writer.WriteConstant("</tr>");
            }
            writer.WriteConstant("</table>");
            break;
            ....... ......
    }
    

    附上源码和dll:
    dll下载
    源码下载

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

    参考文献:
    原项目的github
    用上CommonMark.NET,.NET平台终于有了好用的markdown引擎

  • 相关阅读:
    今天VSS 了一把
    中文字母检索
    当心! 您也可能犯得js错 eval()不等于eval("")!
    腾讯微博邀请码2010年6月9日11:14:28
    存储过程原理
    腾讯微博邀请码2010年5月25日16:44:24
    《QQ我的好友想到的信息架构》
    8小时之外(Beyond the 8 Hours)
    超搞笑漫画比喻!如果浏览器是出行工具
    Nginx环境下配置PHP使用的SSL认证(https)
  • 原文地址:https://www.cnblogs.com/ace-lj/p/5363001.html
Copyright © 2011-2022 走看看