Python Markdown解析利器----mistune详细用法记录

小试牛刀

import mistune
from mistune.directives import DirectiveToc,DirectiveInclude
from mistune.plugins import plugin_footnotes,\
plugin_strikethrough,plugin_table,plugin_url,\
plugin_task_lists,plugin_def_list,plugin_abbr

renderer = mistune.HTMLRenderer()
markdown = mistune.create_markdown(renderer,escape=False,plugins=[DirectiveToc(),
                                               DirectiveInclude(),# toc支持
                                               plugin_footnotes, # 注脚
                                               plugin_strikethrough, # 删除线
                                               plugin_table, # 表格
                                               plugin_url, # 链接
                                               plugin_task_lists , # 任务列表
                                               plugin_def_list, # 自定义列表
                                               plugin_abbr, # 缩写
                                               ]
                            )
mdText = '''

@[toc]
# H1 title
~~here is the content~~
<https://typlog.com/>
https://typlog.com/
[链接](https://typlog.com/)

content in paragraph with footnote[^1] markup.

[^1]: footnote explain

## H2 title

- [x] item 1
- [ ] item 2

First term
: First definition
: Second definition

Second term
: Third definition

# H1 title

The HTML specification is maintained by the W3C.

*[HTML]: Hyper Text Markup Language
*[W3C]: World Wide Web Consortium

.. include:: study.md



'''

md_HTML = markdown(mdText)

with open("a.html","w+",encoding="utf-8") as f:
    f.write(md_HTML)

上述代码你跑成功了吗?是不是还有许多不解的地方?没关系下面有你想要的在这里插入图片描述

开始使用mistune

mistune简单使用

import mistune

mistune.html(YOUR_MARKDOWN_TEXT)

mistune高级用法(自定义mistune)

import mistune

markdown = mistune.create_markdown()
markdown('YOUR_MARKDOWN_TEXT')

参数

参数释义默认值备注
escapeHTML转义TRUE默认情况下将html文本转义,如:1
plugins启用的插件功能None导入插件后添加到plugins中启用插件,他的传入值为列表,如:2
hard_wrap将每一新行分成<br>False启用后md文件中的每一行都会解析成单独一行
renderer默认选项有AST解析器mistune.AstRenderer()和HTML解析器mistune.HTMLRenderer() , 也可以自定义3

mistune中插件

插件使用方法(以 删除线(strikethrough) 为例)

mistune.html() 默认支持strikethrough. 创建自己的markdown实例:

markdown = mistune.create_markdown(plugins=['strikethrough'])

其他创建你自己的markdown实例的方法:

from mistune.plugins import plugin_strikethrough

renderer = mistune.HTMLRenderer()
markdown = mistune.Markdown(renderer, plugins=[plugin_strikethrough])

插件包名

内置插件

序号插件目录引用
1.删除线(strikethrough)from mistune.plugins import plugin_strikethrough
2注脚(footnotes)from mistune.plugins import plugin_footnotes
3表格(table)from mistune.plugins import plugin_table
4链接(url)from mistune.plugins import plugin_url
5任务列表(task_lists)from mistune.plugins import plugin_task_lists
6描述列表(def_list)from mistune.plugins import plugin_def_list
7缩写(abbr)from mistune.plugins import plugin_abbr

删除线(strikethrough)

语法:
~~here is the content~~
显示:
here is the content

注脚(footnotes)

语法: content in paragraph with footnote[^1] markup. [^1]: footnote explain
显示:

content in paragraph with footnote4 markup.

表格(table)

语法:
简易式表格 :
Simple formatted table:
First Header | Second Header
------------- | -------------
Content Cell | Content Cell
Content Cell | Content Cell
复杂的表格:
Complex formatted table:
| First Header | Second Header |
| ------------- | ------------- |
| Content Cell | Content Cell |
| Content Cell | Content Cell |
表格对齐
Align formatted table:
简易写法
Left Header | Center Header | Right Header
:----------- | :-------------: | ------------:
Conent Cell | Content Cell | Content Cell
复杂写法
| Left Header | Center Header | Right Header |
| :---------- | :-------------: | ------------: |
| Conent Cell | Content Cell | Content Cell |
显示:
First Header | Second Header
------------- | -------------
Content Cell | Content Cell
Content Cell | Content Cell

Left HeaderCenter HeaderRight Header
Conent CellContent CellContent Cell

链接(url)

语法

允许使用默认的链接创建url
For instance, https://typlog.com/
显示:

For instance , https://typlog.com/

任务列表

语法
- [x] item 1
- [ ] item 2
显示:

  • item 1
  • item 2

描述列表

语法
First term
: First definition
: Second definition

Second term
: Third definition
显示:

First term
First definition
Second definition
Second term
Third definition

缩写(abber)

语法
The HTML specification is maintained by the W3C.
*[HTML]: Hyper Text Markup Language
*[W3C]: World Wide Web Consortium
显示:

The HTML specification is maintained by the W3C.

解析器

使用解析器

你可以使用自己的渲染器来自定义HTML的输出.创建一个mistune.HTMLRenderer的子类:

import mistune
from mistune import escape
class MyRenderer(mistune.HTMLRenderer):
    def codespan(self, text):
        if text.startswith('$') and text.endswith('$'):
            return '<span class="math">' + escape(text) + '</span>'
        return '<code>' + escape(text) + '</code>'

# 使用自定义解析器
markdown = mistune.create_markdown(renderer=MyRenderer())
print(markdown('hi `$a^2=4$`'))

可用的解析器功能列表

1.内联级 inline level
text(self, text)
link(self, link, text=None, title=None)
image(self, src, alt=“”, title=None)
emphasis(self, text)
strong(self, text)
codespan(self, text)
linebreak(self)
newline(self)
inline_html(self, html)
2.块级 block level
paragraph(self, text)
heading(self, text, level)
heading(self, text, level, tid) # when TOC directive is enabled
thematic_break(self)
block_text(self, text)
block_code(self, code, info=None)
block_quote(self, text)
block_html(self, html)
block_error(self, html)
list(self, text, ordered, level, start=None)
list_item(self, text, level)
3.由删除插件提供 provided by strikethrough plugin
strikethrough(self, text)
4.由表格插件提供 provide by table plugin
table(self, text)
table_head(self, text)
table_body(self, text)
table_row(self, text)
table_cell(self, text, align=None, is_head=False)
5.由注胶插件提供 provided by footnotes plugin
footnote_ref(self, key, index)
footnotes(self, text)
footnote_item(self, text, key, index)
6.确定最终呈现内容(定义输出) Finalize rendered content (define output)
finalize(self, data)

自定义渲染器

Midtune 支持开发者自定义渲染器功能,例如,创建一个代码高亮渲染器

import mistune
from pygments import highlight
from pygments.lexers import get_lexer_by_name
from pygments.formatters import html


class HighlightRenderer(mistune.HTMLRenderer):
    def block_code(self, code, lang=None):
        if lang:
            lexer = get_lexer_by_name(lang, stripall=True)
            formatter = html.HtmlFormatter()
            return highlight(code, lexer, formatter)
        return '<pre><code>' + mistune.escape(code) + '</code></pre>'

markdown = mistune.create_markdown(renderer=HighlightRenderer())

print(markdown('```python\nassert 1 == 1\n```'))

创建一个大纲提取渲染器

import mistune
from mistune import escape


class TocObj:
    toc = []
    index = 0

    def add(self, text, level):
        anchor = '#toc%s%s' % (level, self.index)
        self.index += 1
        self.toc.append({'anchor': anchor, 'level': level, 'text': text})
        return anchor

    # // 使用堆栈的方式处理嵌套的ul,li,level即ul的嵌套层次,1是最外层
    # // <ul>
    # //   <li></li>
    # //   <ul>
    # //     <li></li>
    # //   </ul>
    # //   <li></li>
    # // </ul>
    def toHTML(self):
        levelStack = []
        result = ''

        def addStartUL():
            nonlocal result
            result += '<ul>\n'

        def addEndUL():
            nonlocal result
            result += '</ul>\n'

        def addLI(anchor, text):
            nonlocal result
            result += '<li><a href="#' + anchor + '">' + text + '</a></li>\n'

        for item in self.toc:
            if item['level'] in levelStack:
                levelIndex = levelStack.index(item['level'])
            else:
                levelIndex = -1
            #  没有找到相应level的ul标签,则将li放入新增的ul中
            if levelIndex == -1:
                levelStack.insert(0, item['level'])
                addStartUL()
                addLI(item['anchor'], item['text'])
            #  找到了相应level的ul标签,并且在栈顶的位置则直接将li放在此ul下
            elif levelIndex == 0:
                addLI(item['anchor'], item['text'])
            #  找到了相应level的ul标签,但是不在栈顶位置,需要将之前的所有level出栈并且打上闭合标签,最后新增li
            else:
                while levelIndex > 0:
                    levelIndex = levelIndex - 1
                    levelStack.pop(0)
                    addEndUL()
                addLI(item['anchor'], item['text'])
        #  如果栈中还有level,全部出栈打上闭合标签
        while len(levelStack) > 0:
            levelStack.pop(0)
            addEndUL()
        # 清理先前数据供下次使用
        self.toc = []
        self.index = 0
        return result


tocObj = TocObj()


class MyRenderer(mistune.HTMLRenderer):
    def heading(self, text, level):
        global tocObj
        anchor = tocObj.add(text, level)
        # print(text, level)
        return '<a id=%(anchor)s class="anchor-fix"></a><h%(level)s>%(text)s</h%(level)s>\n' % {'anchor': anchor,
                                                                                                'level': level,
                                                                                                'text': text}


# 使用自定义解析器
markdown = mistune.create_markdown(renderer=MyRenderer())
print(markdown('# 一级标题 1 \n ## 二级标题 1 \n ## 二级标题 2 \n # 一级标题 2 \n hi `$a^2=4$`'))
print(tocObj.toHTML())

上面的代码其实是我按照网上相关js的代码简单改写得来的,放一下原本的js的代码,以免我水平不足有误导大家的地方

self.importScripts("./js/mermaid.min.js");
let rendererMD = new marked.Renderer();
//重写heading,添加一个toc方法
rendererMD.heading = function (text, level, raw) {
    var anchor = tocObj.add(text, level);
    return `<a id=${anchor} class="anchor-fix"></a><h${level}>${text}</h${level}>\n`;
};
marked.setOptions({
    renderer: rendererMD,
    gfm: true,//它是一个布尔值,默认为true。允许 Git Hub标准的markdown.
    tables: true,//它是一个布尔值,默认为true。允许支持表格语法。该选项要求 gfm 为true。
    breaks: false,//它是一个布尔值,默认为false。允许回车换行。该选项要求 gfm 为true。
    pedantic: false,//它是一个布尔值,默认为false。尽可能地兼容 markdown.pl的晦涩部分。不纠正原始模型任何的不良行为和错误。
    sanitize: false,//它是一个布尔值,默认为false。对输出进行过滤(清理),将忽略任何已经输入的html代码(标签)
    smartLists: true,//它是一个布尔值,默认为false。使用比原生markdown更时髦的列表。 旧的列表将可能被作为pedantic的处理内容过滤掉.
    smartypants: false//它是一个布尔值,默认为false。使用更为时髦的标点,比如在引用语法中加入破折号。
});

const tocObj = {
    add: function (text, level) {
        var anchor = `#toc${level}${++this.index}`;
        this.toc.push({anchor: anchor, level: level, text: text});
        return anchor;
    },
    // 使用堆栈的方式处理嵌套的ul,li,level即ul的嵌套层次,1是最外层
    // <ul>
    //   <li></li>
    //   <ul>
    //     <li></li>
    //   </ul>
    //   <li></li>
    // </ul>
    toHTML: function () {
        let levelStack = [];
        let result = '';
        const addStartUL = () => {
            result += '<ul>';
        };
        const addEndUL = () => {
            result += '</ul>\n';
        };
        const addLI = (anchor, text) => {
            result += '<li><a href="#' + anchor + '">' + text + '<a></li>\n';
        };

        this.toc.forEach(function (item) {
            let levelIndex = levelStack.indexOf(item.level);
            // 没有找到相应level的ul标签,则将li放入新增的ul中
            if (levelIndex === -1) {
                levelStack.unshift(item.level);
                addStartUL();
                addLI(item.anchor, item.text);
            } // 找到了相应level的ul标签,并且在栈顶的位置则直接将li放在此ul下
            else if (levelIndex === 0) {
                addLI(item.anchor, item.text);
            } // 找到了相应level的ul标签,但是不在栈顶位置,需要将之前的所有level出栈并且打上闭合标签,最后新增li
            else {
                while (levelIndex--) {
                    levelStack.shift();
                    addEndUL();
                }
                addLI(item.anchor, item.text);
            }
        });
        // 如果栈中还有level,全部出栈打上闭合标签
        while (levelStack.length) {
            levelStack.shift();
            addEndUL();
        }
        // 清理先前数据供下次使用
        this.toc = [];
        this.index = 0;
        return result;
    },
    toc: [],
    index: 0
};


// 执行markdown解析线程
self.addEventListener('message', e => { // 接收到消息
    //console.log(); // Greeting from Main.js,主线程发送的消息
    let content = e.data
    content = marked(content);
    tocHtml = "<div class='toc'><h3>文章目录</h3> " + tocObj.toHTML() + "</div>";
    content = content.replace(/<p>\[Toc]<\/p>/g,tocHtml);
    self.postMessage(content); // 向主线程发送消息
});

创建插件

Mistune有一些内置插件,您可以查看Mistune/plugins中的源代码,了解如何编写插件。让我们以GitHub Wiki链接为例:

一个mistune插件示例:

# 为Wiki链接定义正则表达式 define regex for Wiki links
import mistune
WIKI_PATTERN = (
    r'\[\['                   # [[
    r'([\s\S]+?\|[\s\S]+?)'   # Page 2|Page 2
    r'\]\](?!\])'             # ]]
)

# 定义如何解析匹配项 define how to parse matched item
def parse_wiki(inline, m, state):
    # ``inline`` is ``md.inline``, see below
    # "m"是匹配的正则表达式项 ``m`` is matched regex item
    text = m.group(1)
    title, link = text.split('|')
    return 'wiki', link, title

# 定义如何渲染HTML define how to render HTML
def render_html_wiki(link, title):
    return f'<a href="{link}">{title}</a>'

def plugin_wiki(md):
    # 这是一个内联语法,因此我们将wiki规则注册到md.inline中
    # this is an inline grammar, so we register wiki rule into md.inline
    # 语法: md.inline.register_rule(name, 正则表达式, 函数[解析匹配项])
    # 注意名字要一直匹配
    md.inline.register_rule('wiki', WIKI_PATTERN, parse_wiki)
    
    # 将wiki规则添加到活动规则中
    # add wiki rule into active rules
    md.inline.rules.append('wiki')

    # 添加HTML渲染器 add HTML renderer
    if md.renderer.NAME == 'html':
        md.renderer.register('wiki', render_html_wiki)

# 使用这个插件 use this plugin
markdown = mistune.create_markdown(plugins=[plugin_wiki])

资源

名称链接
官方说明https://mistune.readthedocs.io/en/v2.0.4/guide.html
mistune GitHub主页https://github.com/lepture/mistune
mistune 作者写的其他插件https://github.com/lepture/mistune-contrib

  1. markdown('<div>hello</div>') 返回 '<div>hello</div>' ↩︎

  2. markdown = mistune.create_markdown(plugins=['strikethrough']) # 启用删除线插件 ↩︎

  3. renderer = mistune.HTMLRenderer() markdown = mistune.create_markdown(renderer) ↩︎

  4. footnote explain ↩︎

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

盧瞳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值