• Python使用Mistune对markdown自定义规则解析


    Mistune——更快的markdown解析器

    在Python中有很多markdown解析器,以前我一直使用的是Python-markdown,一个纯Python实现的markdown解析器,别的不说,慢的要死倒是真的。每次点击保存后,都要响应很久,我开始一直以为是我的vps在国外导致的,后来还用了Mistune才知道,不是网速的问题,是解析器的速度问题。

    没有对比就没有伤害,Mistune是所有纯Python实现中最快的一个。在纯Python环境中,几乎比Python- markdown快4倍,在Cython的帮助下,几乎快5倍。现在我使用了CPython,几乎是点击完保存的一瞬间,就解析完了,可以说感觉是很明显的。

    基础用法

    一个简单的栗子:

    import mistune
    
    mistune.markdown('I am using **mistune markdown parser**')
    # output: <p>I am using <strong>mistune markdown parser</strong></p>
    

    如果关心性能,官方推荐使用对象实例化后在进行调用

    import mistune
    
    markdown = mistune.Markdown()
    markdown('I am using **mistune markdown parser**')
    

    选择项

    在使用mistune.Renderer的时候会有一些选择项提供修改

    renderer = mistune.Renderer(escape=True, hard_wrap=True)
    # use this renderer instance
    markdown = mistune.Markdown(renderer=renderer)
    markdown(text)
    
    • escape: 如果设置为False,则不会转义所有原始html标记。
    • hard_wrap: 如果设置为True,它将具有GFM换行功能。所有新行都将替换为<br>标记。GFM跟标准MD一样,行尾不允许直接回车换行,必须是 或者空格空格
    • use_xhtml: 如果设置为True,则所有标记都将使用xhtml,例如:<hr />
    • parse_block_html:只解析block级别的。
    • parse_inline_html: 只解析inline级别的。

    Renderer(渲染器)

    官方提供了渲染器,当然你也可以继承官方的Renderer然后自己重写或者添加一些方法,这里给了一个官网给出的栗子,是一个给所有代码块添加highlighting标签的栗子。

    import mistune
    from pygments import highlight
    from pygments.lexers import get_lexer_by_name
    from pygments.formatters import html
    
    class HighlightRenderer(mistune.Renderer):
        def block_code(self, code, lang):
            if not lang:
                return '
    <pre><code>%s</code></pre>
    ' % 
                    mistune.escape(code)
            lexer = get_lexer_by_name(lang, stripall=True)
            formatter = html.HtmlFormatter()
            return highlight(code, lexer, formatter)
    
    renderer = HighlightRenderer()
    markdown = mistune.Markdown(renderer=renderer)
    print(markdown('```python
    assert 1 == 1
    ```'))
    

    下面是关于解析内容的很关键的定义,一个是块级解析(Block Level),一个是小跨度级解析(Span Level),也就是每句话中间出现的那种markdown解析,加粗什么的,还有一个是脚注(Footnotes)

    Block Level

    块级的API如下:

    block_code(code, language=None) #代码块
    block_quote(text) #引用块
    block_html(html) #原生html?
    header(text, level, raw=None) # 不知道是啥
    hrule() # 不知道是啥
    list(body, ordered=True) # 不知道是啥
    list_item(text) # 不知道是啥
    paragraph(text) # 段落
    table(header, body) # 表格
    table_row(content) # 表格行
    table_cell(content, **flags) # 表格单元
    

    Span Level

    块级的API如下:

    autolink(link, is_email=False) #引用链接
    codespan(text) #行级code
    double_emphasis(text) #加粗
    emphasis(text) #斜体
    image(src, title, alt_text) #图片
    linebreak() #不知道
    newline() #新的一行?
    link(link, title, content) #引用链接
    strikethrough(text) #不知道
    text(text) #普通文字
    inline_html(text) #内嵌HTML
    

    Footnotes

    脚注的API如下:

    footnote_ref(key, index)
    footnote_item(key, text)
    footnotes(text)
    

    自定义规则

    下面就是自定义规则了,我们大概了解了每个API,官方源码里面主要分了以下几个类

    • BlockGrammar:关于块级的语法正则定义
    • BlockLexer:块级词法分析器
    • InlineGrammar:关于行级的语法正则定义
    • InlineLexer:行级词法分析器
    • Markdown:Markdown解析
    • Renderer:解析器

    在这里,我举一个真实的栗子来讲解,首先抛出问题

    问题:我在使用mathtype的时候,书写公式,例如这个公式||x||_1= sum_{i=0}^{n}|x_i|,这是L1范数的公式,现在解析肯定没有问题了,我已经修复了,但如果是以前,会由于||x||后面的字符_sum后面的字符_,匹配到markdown中就是斜体的定义,那么我的公式就会变为

    ||x|| @1= sum@ {i=0}^{n}|x_i|​

    这个样子。所以为了解决这个问题,我要重写有关于下划线_和乘号*的markdown语法。

    解决办法:

    首先定位一下,主要引起这个的有两个,一个是加粗,一个是斜体,所以我重写他们。

    1. 定义自己的InlineLexer,继承InlineLexer
    2. 找到规则double_emphasisemphasis,我将加粗改写为了只允许**框住,斜体改写为了@框住;
    3. 加入到default_rules这个list里面;
    4. 重写输出函数output_double_emphasisoutput_emphasis
    class MyInlineLexer(InlineLexer):
        def enable_delete_em(self):
            self.rules.double_emphasis = re.compile(
                r'*{2}([sS]+?)*{2}(?!*)'  # **word**
            )
            self.rules.emphasis = re.compile(
                r'@((?:**|[^*])+?)@(?!*)'  # @word@
            )
            self.default_rules.insert(3, 'double_emphasis')
            self.default_rules.insert(3, 'emphasis')
    
        def output_double_emphasis(self, m):
            text = m.group(1)
            return self.renderer.double_emphasis(text)
    
        def output_emphasis(self, m):
            text = m.group(1)
            return self.renderer.emphasis(text)
    

    然后在解析markdown的时候

    renderer = Renderer()
    inline = MyInlineLexer(renderer)
    inline.enable_delete_em()
    markdown = mistune.Markdown(renderer=renderer, inline=inline)
    
    1. 实例化Renderer;
    2. 实例化自己的词法分析器;
    3. 调用enable_delete_em()重写对应的地方;
    4. 最后,实例化markdown,传入对应的renderer与inline即可。

    Reference

    Mistune文档

    Markdown Parsers in Python

  • 相关阅读:
    【餐厅】 What kind of food would you like to eat tonight?
    深入分析总线设备驱动模型的框架
    总线设备驱动模型
    Qt工程管理
    USB摄像头驱动框架分析
    浅析struct device结构体
    一、mysql下载与安装
    vsCode创建自己的代码模板
    vsCode多选多个元素进行统一修改
    博客园添加目录
  • 原文地址:https://www.cnblogs.com/harrylyx/p/12395259.html
Copyright © 2020-2023  润新知