Python使用Mistune对markdown自定义规则解析
1.Mistune——更快的markdown解析器
在Python中有很多markdown解析器,以前我一直使用的是Python-markdown ,一个纯Python实现的markdown解析器,别的不说,慢的要死倒是真的。每次点击保存后,都要响应很久,我开始一直以为是我的vps在国外导致的,后来还用了Mistune才知道,不是网速的问题,是解析器的速度问题。
没有对比就没有伤害,Mistune 是所有纯Python实现中最快的一个。在纯Python环境中,几乎比Python- markdown快4倍,在Cython的帮助下,几乎快5倍。现在我使用了CPython,几乎是点击完保存的一瞬间,就解析完了,可以说感觉是很明显的。
2.基础用法
一个简单的例子:
import mistune
mistune.markdown('I am using **mistune markdown parser**')
如果关心性能,官方推荐使用对象实例化后在进行调用
import mistune
markdown = mistune.Markdown()
markdown('I am using **mistune markdown parser**')
3.选择项
在使用mistune.Renderer 的时候会有一些选择项提供修改
renderer = mistune.Renderer(escape=True, hard_wrap=True)
markdown = mistune.Markdown(renderer=renderer)
markdown(text)
- escape: 如果设置为False,则不会转义所有原始html标记。
- hard_wrap: 如果设置为True,它将具有GFM换行功能。所有新行都将替换为
<br> 标记。GFM跟标准MD一样,行尾不允许直接回车换行,必须是\n\n 或者空格空格\n - use_xhtml: 如果设置为True,则所有标记都将使用xhtml,例如:
<hr /> - parse_block_html:只解析block级别的。
- parse_inline_html: 只解析inline级别的。
4.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 '\n<pre><code>%s</code></pre>\n' % \
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\nassert 1 == 1\n```'))
下面是关于解析内容的很关键的定义,一个是块级解析(Block Level),一个是小跨度级解析(Span Level),也就是每句话中间出现的那种markdown解析,加粗什么的,还有一个是脚注(Footnotes)
5.Block Level
块级的API如下:
block_code(code, language=None)
block_quote(text)
block_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)
6.Span Level
块级的API如下:
autolink(link, is_email=False)
codespan(text)
double_emphasis(text)
emphasis(text)
image(src, title, alt_text)
linebreak()
newline()
link(link, title, content)
strikethrough(text)
text(text)
inline_html(text)
7.Footnotes
脚注的API如下:
footnote_ref(key, index)
footnote_item(key, text)
footnotes(text)
8.自定义规则
下面就是自定义规则了,我们大概了解了每个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语法。
有想学python编程但却苦无方法,可以跟我一起来学python
带你零基础入门 解决办法:
首先定位一下,主要引起这个的有两个,一个是加粗,一个是斜体,所以我重写他们。
- 定义自己的
InlineLexer ,继承InlineLexer ; - 找到规则
double_emphasis 和emphasis ,我将加粗改写为了只允许** 框住,斜体改写为了@ 框住; - 加入到
default_rules 这个list 里面; - 重写输出函数
output_double_emphasis 和output_emphasis 。
class MyInlineLexer(InlineLexer):
def enable_delete_em(self):
self.rules.double_emphasis = re.compile(
r'\*{2}([\s\S]+?)\*{2}(?!\*)'
)
self.rules.emphasis = re.compile(
r'\@((?:\*\*|[^\*])+?)\@(?!\*)'
)
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)
-
实例化Renderer; -
实例化自己的词法分析器; -
调用enable_delete_em()重写对应的地方; -
最后,实例化markdown,传入对应的renderer与inline即可。
最后,感谢您的阅读。您的每个点赞、留言、分享都是对我们最大的鼓励,笔芯~
如有疑问,欢迎在评论区一起讨论!
|