# 背景 Markdown 是一个轻量的标记语言,由于它的语法简洁,因此深受程序员喜爱。程序员一般用 Markdown 写文档,写博客,做笔记。 Markdown 语法没有一个统一的标准,因此会出现编辑器解析器语法不兼容的问题,常见的 Markdown 标准是 [CommonMark](https://commonmark.org/) 标准,除此之外还有一些特定平台支持的 Markdown: - Discourse - GitHub - GitLab - Reddit CommonMark 语法标准可以参考 [CommonMark Spec](https://spec.commonmark.org/) 。 # Markdown 文档的组成 一篇 Markdown 文章由块级元素组成,例如自然段,代码块,数学公式块,列表,表格,预定义样式块,标题等。块级元素又可以分为两类: - 内容块:不再包含其他块级元素。例如:代码块,数学公式块,表格,段落。 - 容器块:能包含内容块,但不能包含容器块。例如:预定义样式块。 每个块级元素有特定的内部结构,例如: - 代码块:可能包含语言,语法高亮,行号等。 - 公式块:latex解析。 - 富文本段:常见的格式。 对于富文本文本段,它由行内元素组成:纯文字,加粗,图片,行内代码,行内公式,链接,Emoji。因此 Markdown 文档的解析可以分为两个步骤: - 解析文档得到块级元素。 - 解析块级元素。 # 行内元素(Inline) ## 行内代码(Code spans) 由一对反引号括起来的内容: ```markdown `hi` ``` ## Emoji 本解析器不支持Emoji :+1: 语法,请直接复制粘贴相关表情。 ## 行内公式(Inline math) 由一对美元符括起来的部分。 ```markdown $e^{i\pi)+1=0$ ``` ## 自动链接(Autolinks) 由尖括号括起来的文字: ```markdown ``` 会被转为: ```html http://foo.bar.baz ``` ## 加粗(strong emphasis) 由一对双星号括起来的内容: ```shell **in strong** ``` ## 链接(Links) 链接的语法如下所示: ```markdown [link](/uri "title") ``` 会解析成: ```html link ``` ## 图片(Images) 图片语法如下: ```markdown ![foo](url "title") ``` 会解析成: ```html

foo

``` ## 普通文本(Text) 不是以上行内元素组成的字符串就会被当做普通文本。 # 块级元素 接下来我们来看看一些块级元素的定义,这里定义的块级元素参考了 CommonMark,但并没有完全遵守,我们还自定义了一些块级元素。 块级元素可以分为两种,一种是容器块,一种是内容块。它们之间的区别是容器块可能包含其他块,内容块不包含其他块。 ## 标题(ATX headings) 由 1~3 个 `#` 开头,然后是空格,紧接着标题内容,典型示例: ```markdown # foo ## foo ### foo ``` 解析为: ```html

foo

foo

foo

``` ## 代码块(Fenced code blocks) 代码块由三个反引号开始,三个反引号结尾,它们不能在同一行。起始单引号后可以跟代码语言名字。 ~~~markdown ```ruby def foo(x) return 3 end ``` ~~~ ## 公式块(Display maths) 代码块由两个美元符开始,由两个美元符结尾,它们不能在同一行。 ```markdown $$ f(x)=1+x+\frac{x^2}{2} $$ ``` ## 列表(Lists) 由 `-` 加一个空格开始的连续不断的行。 目前只定义了无序列表。 ## 预定义样式(Pres) 预定义样式由两个百分号开始,由两个百分号结尾,它们不能在同一行。起始百分好可以跟预定义样式名: ```markdown %%warn 这里还可以定义标题 预定义样式里面可能会有如下块级元素 代码块 公式块 列表 自然段 %% ``` 预定义的样式名有: ```shell 状态类: 'quote' | '引用' 'warn' | '警告' 'info' | '提示' 'tip' | '技巧' 'think' | '思考 数学类: 'lem' | '定理' 'pro' | '证明' 'def' | '定义' 'thm' | '定理' 'sol' | '解' 'cor' | '推论' ``` ## 习题(Exercises) 习题由两个问号开始,由两个问号结尾,它们不能在同一行,起始问号后可以跟习题类型: ```markdown ??ms 这里是主题干。 - 这里的列表定义选项或者小问 - 另一个小问 - 小问之间不能有空行 - 没有小问的用空列表,以便与答案列表区分 - 这里的列表定义相应小问的答案 - 用空行与上面的的列表隔开 ?? ``` 支持的题型有: - ss:单选题 - ms:多选题 - co:填空题 - qa:问答题 ## 自然段(Paragraphs) 普通的块级元素,不是以上块级元素都被当做自然段。 # 解析算法 第一步:解析块级元素 第二步:对于块级元素,调用相应解析器