1 python markdown 解析器

  • mistletoe Star 665
    • 主要支持 CommonMark Markdown
  • mistune Star 2.3k
    • 较量级
  • markdown_it Start 16.1k
    • javascript 库
  • markdown Star 3.4k
    • 对 pandoc 支持相对较好
    • 功能比较强大
    • 帮助页:https://python-markdown.github.io/
  • markdown2 Start 2.5k
    • 用于转 html

2 mistune

2.1 github 地址

https://github.com/lepture/mistune

2.2 输入 markdown,输出 html 文本。

1
2
3
import mistune
mistune.markdown('I am using **mistune markdown parser**')
# 输出: <p>I am using <strong>mistune markdown parser</strong></p>

mistune 还支持插件,显示更复杂的界面。

主要这是一个纯 python 的,不涉及前端工具链。

2.3 输出树型结构

1
2
3
4
import mistune

markdown = mistune.create_markdown(renderer=None)
markdown(markdown_text)

2.4 处理特定格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import mistune
from mistune import HTMLRenderer

class MyRenderer(HTMLRenderer):
def heading(self, text, level, **attrs):
print('heading', text, level)
return '<h%d>%s</h%d>\n' % (level, text, level)

markdown = mistune.create_markdown(renderer=MyRenderer())
content2 = '''
# 测试一下
## 测试两下
'''
print(markdown(content2))

解决方法说明

注意

有一些包含关系,如果使用 render,可能被忽略掉了。

2.6 参考

Mistune中文指导文档

1
$ pip install mistune

3 commonmark

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import commonmark
from commonmark.dump import dumpAST, dumpJSON

# 创建一个 CommonMark 文本
commonmark_text = """
# 标题
这是一个 *CommonMark* 示例。

- 列表项1
- 列表项2
"""

parser = commonmark.Parser()
ast = parser.parse(commonmark_text)
dumpAST(ast)

AST 意为抽象语法树

pandocfilter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# my_filter
import pandocfilters as pf

def my_filter(key, value, format, meta):
if key == 'Table':
print(key)
print(value)
elif key == 'Header':
print(key)
print(value)
else:
print('key', key)
print('value', value)

if __name__ == "__main__":
pf.toJSONFilter(my_filter)

运行:

1
2
3
pandoc -s xx.docx -f docx -t json|python my_filter.py
#
pandoc -s xx.md -f markdown -t json|python my_filter.py

选库

选库的核心逻辑如下:

  • 编码:markdown 语法非常简单,因此不需要特定库来输出
  • 解码:理论上来说,也可以自己实现解码,按行解析可能有以下问题
    • 代码块跨行
    • 引用块跨行
    • 表格跨行
  • 转换:上述多数的库目标在于将 markdown 转换成其它格式,而多数是转换成 html 格式

解决方法:

  • 使用如 python-markdown 将文档切分成 block
  • 切块以两个回车作为 block 的分界,可能将程序段一分为二

讨论:

  • 如果 markdown 是我们自己写的,则可能的问题都可以处理掉:
    • 如多余的空行
    • 多余的字体,加粗,斜体设置

Markdown 格式

列表的显示只需要在文字前加上 - 或 * 即可变为无序列表,有序列表则直接在文字前加 1. 2. 3. 符号要和文字之间加上一个字符的空格。

链接为:

多级编号,使用四个空格,或者一个 Tab 缩进。

1
2
3
4
5
1. 一级项目
1. 二级项目
1. 三级项目
2. 二级项目
2. 一级项目

如果识别了目录或者附录,可将其作为一级标题。

因此优先级是:

第一级:各级标题,目录,附录

第二级:有序列表,无序列表,按缩进分子级

其它:包含关键字的短行,数字标号,如 1,2,3

问题:

  • 无法确定数字/关键字标号,与文档中标题的格式的上下级关系
    • 在所在块内部,继续向下分级
    • 设立相对级别号和绝对级别号
  • 有时候库解决出来不对
    • 这种情况下,也可能是我们转换生成的 markdown 文件本身格式有问题
    • 可以做一个包含正常格式的文档,用不同解析器测试其效果
  • 多级编号,都是 "1." 看起来很怪
    • 如果能确定,可以使用多级无序编号格式,把序号作为标题的一部分
1
2
3
4
5
6
7
8
9
- (a) 第一层
- (1) 第二层1
- (2) 第二层2
- (b) 第二层
- ...
```

* 目录在 Markdown 中与正文如何区分

  • 标题1
  • 标题2
  • 标题3
    1
    2
    3
    4
    5
    6

    可固定写成上述模式,并在内部在特殊格式存储,并可对比正文的标题,进行对齐

    * 表格
    * 不用太考虑排版,主要是让使用到的解码库识别成表即可

    # 表头 header = ["姓名", "年龄", "城市"] # 数据 data = [ ["Alice", 25, "New York"], ["Bob", 30, "San Francisco"], ["Charlie", 22, "Los Angeles"],]

生成Markdown表格

markdown_table = "| " + " | ".join(header) + " |" markdown_table += "| " + " | ".join(["---"] * len(header)) + " |"

for row in data: markdown_table += "| " + " | ".join(map(str, row)) + " |"

打印Markdown表格

print(markdown_table) ```