Markdown 是一种用于编写结构化文档的纯文本格式,
基于电子邮件中指示格式的约定
和新闻组帖子。它是由约翰·格鲁伯(John Gruber)开发的(与
在 Aaron Swartz 的帮助下)并于 2004 年以
语法描述
和一个 Perl 脚本( Markdown.pl
) 用于将 Markdown 转换为
HTML。在接下来的十年里,数十个实施
以多种语言开发。有的扩展了原来的
具有脚注、表格和约定的 Markdown 语法
其他文档元素。有些允许 Markdown 文档
以 HTML 以外的格式呈现。像 Reddit 这样的网站,
StackOverflow 和 GitHub 有数百万人使用 Markdown。
Markdown 开始在网络之外使用,用于撰写书籍,
文章、幻灯片、信件和讲义。
Markdown 与许多其他轻量级标记的区别是什么 语法,往往更容易编写,在于它的可读性。 正如格鲁伯所写:
Markdown 格式化语法的首要设计目标是 使其尽可能可读。这个想法是 Markdown 格式的文档应该可以按原样发布,如下所示 纯文本,看起来没有用标签标记 或格式说明。 ( https://daringfireball.net/projects/markdown/ )
可以通过比较一个样本来说明这一点 AsciiDoc 与 Markdown 的等效示例。这是一个示例 AsciiDoc 手册中的 AsciiDoc:
1. List item one.
+
List item one continued with a second paragraph followed by an
Indented block.
+
.................
$ ls *.sh
$ mv *.sh ~/tmp
.................
+
List item continued with a third paragraph.
2. List item two continued with an open block.
+
--
This paragraph is part of the preceding list item.
a. This list is nested and does not require explicit item
continuation.
+
This paragraph is part of the preceding list item.
b. List item b.
This paragraph belongs to item two of the outer list.
--
这是 Markdown 中的等效内容:
1. List item one.
List item one continued with a second paragraph followed by an
Indented block.
$ ls *.sh
$ mv *.sh ~/tmp
List item continued with a third paragraph.
2. List item two continued with an open block.
This paragraph is part of the preceding list item.
1. This list is nested and does not require explicit item continuation.
This paragraph is part of the preceding list item.
2. List item b.
This paragraph belongs to item two of the outer list.
AsciiDoc 版本可以说更容易编写。你不需要 担心缩进。但是Markdown版本就简单多了 阅读。列表项的嵌套在 源,而不仅仅是在处理后的文档中。
John Gruber 对 Markdown 的规范描述 句法 没有明确指定语法。以下是一些示例 它没有回答的问题:
子列表需要多少缩进?规范说
连续段落需要缩进四个空格,但是
关于子列表不完全明确。人们很自然地认为
它们也必须缩进四个空格,但是 Markdown.pl
做
不需要那样。这并不是一个“极端案例”,并且存在分歧
在这个问题上的实现之间经常会导致意外
真实文档中的用户。 (参见 约翰的评论
格鲁伯 。)
块引用或标题之前是否需要空行? 大多数实现不需要空行。然而, 这可能会导致硬包装文本出现意外结果,并且 还有解析中的歧义(注意一些实现 将标题放在块引用内,而其他则不然)。 (约翰·格鲁伯也曾表示 赞成要求空白 线 。)
缩进的代码块之前是否需要空行?
( Markdown.pl
需要它,但是在
文档,某些实现不需要它。)
paragraph
code?
确定列表项何时获得的确切规则是什么
包裹在 <p>
标签?列表可以部分“松散”,部分“松散”吗?
“紧的”?对于这样的列表我们应该做什么呢?
1. one
2. two
3. three
还是这个?
1. one
- a
- b
2. two
(约翰·格鲁伯(John Gruber)有一些相关评论 这里 。)
列表标记可以缩进吗?有序列表标记可以右对齐吗?
8. item 1
9. item 2
10. item 2a
这个列表的第二项有主题中断吗? 或者由主题分隔的两个列表?
* a
* * * * *
* b
当列表标记从数字变为项目符号时,我们是否有 两份清单还是一份? (Markdown 语法描述建议有两种, 但 perl 脚本和许多其他实现都会生成一个。)
1. fee
2. fie
- foe
- fum
内联结构标记的优先规则是什么? 例如,以下链接是否有效,或者代码是否跨越 优先?
[a backtick (`)](/url) and [another backtick (`)](/url).
强调和强标记的优先规则是什么 强调?例如,下面的内容应该如何解析?
*foo *bar* baz*
块级和内联级之间的优先级规则是什么 结构?例如,下面的内容应该如何解析?
- `a long code span can contain a hyphen like this
- and it can screw things up`
列表项可以包含章节标题吗? ( Markdown.pl
不
允许这样做,但允许块引用包含标题。)
- # Heading
列表项可以为空吗?
* a
*
* b
可以在块引号或列表项内定义链接引用吗?
> Blockquote [foo].
>
> [foo]: /url
如果同一个引用有多个定义,则需要 优先?
[foo]: /url1
[foo]: /url2
[foo][]
在缺乏规范的情况下,早期实施者咨询了 Markdown.pl
来解决这些歧义。但 Markdown.pl
非常有问题,并且
在很多情况下都给出了明显不好的结果,所以这不是一个
令人满意的规格替代品。
由于没有明确的规范,因此实现存在分歧 相当。结果,用户常常惊讶地发现 在一个系统上以一种方式呈现的文档(例如 GitHub wiki) 在另一个上呈现不同的效果(例如,使用转换为文档 潘多克)。更糟糕的是,因为 Markdown 中没有任何内容 作为“语法错误”,这种分歧通常不会立即被发现。
本文档试图明确指定 Markdown 语法。
它包含许多并排 Markdown 和
HTML。这些旨在兼作一致性测试。一个
附带脚本 spec_tests.py
可用于运行测试
针对任何 Markdown 程序:
python test/spec_tests.py --spec spec.txt --program PROGRAM
由于该文档描述了 Markdown 如何被解析为 抽象语法树,使用抽象是有意义的 语法树的表示而不是 HTML。但 HTML 可以 代表我们需要做出的结构区别,以及 选择 HTML 进行测试使得可以针对其运行测试 无需编写抽象语法树渲染器的实现。
请注意,并非 HTML 示例的每个功能都是由 规格。例如,规范规定什么算作链接 目的地,但它不强制要求非 ASCII 字符 URL 采用百分比编码。要使用自动测试, 实现者需要提供一个符合以下要求的渲染器 规范示例的期望(百分比编码 URL 中的非 ASCII 字符)。但符合要求的实施 可以使用不同的渲染器,也可以选择不使用 对 URL 中的非 ASCII 字符进行百分比编码。
该文档是从文本文件生成的, spec.txt
,写成
在 Markdown 中,带有用于并排测试的小扩展。
剧本 tools/makespec.py
可以用来转换 spec.txt
进入
HTML 或 CommonMark(然后可以转换为其他格式)。
在示例中, →
字符用于表示制表符。
序列 任何字符 都是有效的 CommonMark 文档。
字符 是一个 Unicode 代码点。虽然有些 代码点(例如,组合重音符号)不对应于 直观意义上的字符,所有代码点都算作字符 就本规范而言。
该规范没有指定编码;它认为线条是组合的 字符 而不是字节 。合格的解析器可能是有限的 到某种编码。
一行 是零个 的序列 或多个字符
除了换行之外( U+000A
) 或回车符 ( U+000D
),
后跟行 结束符 或文件末尾。
是 行结束符 换行符 ( U+000A
), 回车
( U+000D
) 后面不跟换行符或回车符和
以下换行。
不包含字符的行或仅包含空格的行
( U+0020
) 或制表符 ( U+0009
),称为 空行 。
本规范中将使用以下字符类定义:
是 Unicode 空白字符 Unicode 中的字符 Zs
一般的
类别或选项卡 ( U+0009
), 换行 ( U+000A
)、换页( U+000C
), 或者
回车( U+000D
)。
Unicode 空白 是一个或多个的序列 Unicode 空白字符 。
一个 选项卡 是 U+0009
。
一个 空格 是 U+0020
。
是 ASCII 控制字符 介于 U+0000–1F
(两个都
包括)或 U+007F
。
标点符号 ASCII
是 !
, "
, #
, $
, %
, &
, '
, (
, )
,
*
, +
, ,
, -
, .
, /
(U+0021–2F),
:
, ;
, <
, =
, >
, ?
, @
(U+003A–0040),
[
, \
, ]
, ^
, _
, `
(U+005B–0060),
{
, |
, }
, 或者 ~
(U+007B–007E)。
是 Unicode 标点符号 Unicode 中的字符 P
(标点符号)或 S
(符号)一般类别。
行中的制表符不会扩展为 空格 。然而, 在空间有助于定义块结构的情况下, 制表符的行为就好像它们被带有制表位的空格替换一样 共 4 个字符。
因此,例如,可以使用制表符代替四个空格 在缩进的代码块中。 (但是请注意,内部 选项卡作为文字选项卡传递,不扩展为 空格。)
在下面的示例中,列表的延续段落 项目用制表符缩进;这有完全相同的效果 四个空格的缩进将:
通常情况下 >
可以跟随以块引用开头
可选地通过一个空格,该空格不被视为
内容。在以下情况下 >
后面跟着一个选项卡,
它被视为扩展成三个空间。
由于这些空间之一被认为是
分隔符, foo
被认为是缩进六个空格
在块引用上下文中,所以我们得到一个缩进
以两个空格开头的代码块。
- foo
- bar
→ - baz
<ul>
<li>foo
<ul>
<li>bar
<ul>
<li>baz</li>
</ul>
</li>
</ul>
</li>
</ul>
出于安全原因,Unicode 字符 U+0000
必须更换
与替换字符( U+FFFD
)。
任何 ASCII 标点字符都可以进行反斜杠转义:
\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~
<p>!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~</p>
其他字符之前的反斜杠被视为文字 反斜杠:
转义字符被视为常规字符并且不会 没有通常的 Markdown 含义:
\*not emphasized*
\<br/> not a tag
\[not a link](/foo)
\`not code`
1\. not a list
\* not a list
\# not a heading
\[foo]: /url "not a reference"
\ö not a character entity
<p>*not emphasized*
<br/> not a tag
[not a link](/foo)
`not code`
1. not a list
* not a list
# not a heading
[foo]: /url "not a reference"
&ouml; not a character entity</p>
如果反斜杠本身被转义,则以下字符不会被转义:
行尾的反斜杠是 硬换行符 :
反斜杠转义在代码块、代码跨度、自动链接或 原始 HTML:
<https://example.com?find=\*>
<p><a href="https://example.com?find=%5C*">https://example.com?find=\*</a></p>
但它们适用于所有其他上下文,包括 URL 和链接标题, 链接引用和 信息字符串 中的 受防护的代码块 :
有效的 HTML 实体引用和数字字符引用 可以用来代替相应的Unicode字符, 但以下情况除外:
代码中无法识别实体和字符引用 块和代码跨度。
实体和字符引用不能代替
定义结构元素的特殊字符
通用标记。例如,虽然 *
可以使用
代替字面意思 *
特点, *
无法替代
*
在强调分隔符、项目符号列表标记或主题中
休息。
符合 CommonMark 解析器不需要存储以下信息 源中是否表示了特定字符 使用 Unicode 字符或实体引用。
实体引用 包括 &
+ 任何有效的
HTML5 实体名称 + ;
。这
文档 https://html.spec.whatwg.org/entities.json
用作有效实体的权威来源
参考文献及其相应的代码点。
& © Æ Ď
¾ ℋ ⅆ
∲ ≧̸
<p> & © Æ Ď
¾ ℋ ⅆ
∲ ≧̸</p>
十进制数字字符
参考
包括 &#
+ 一串 1-7 个阿拉伯数字 + ;
。一个
数字字符引用被解析为相应的
统一码字符。无效的 Unicode 代码点将被替换为
替换字符( U+FFFD
)。出于安全原因,
代码点 U+0000
也将被取代 U+FFFD
。
十六进制数字字符
参考文献 包括 &#
+
任何一个 X
或者 x
+ 1-6 个十六进制数字的字符串 + ;
。
它们也被解析为相应的 Unicode 字符(这
用十六进制数字而不是十进制指定的时间)。
以下是一些非实体的内容:
  &x; &#; &#x;
�
&#abcdef0;
&ThisIsNotDefined; &hi?;
<p>&nbsp &x; &#; &#x;
&#87654321;
&#abcdef0;
&ThisIsNotDefined; &hi?;</p>
尽管 HTML5 确实接受一些实体引用
没有尾随分号(例如 ©
),这些不是
在这里得到认可,因为它使语法变得过于模糊:
不在 HTML5 命名实体列表中的字符串不是 被识别为实体引用:
实体和数字字符引用可以在任何 除了代码跨度或代码块之外的上下文,包括 URL、 链接标题 和 受保护的代码块 信息字符串 :
[foo](/föö "föö")
<p><a href="/f%C3%B6%C3%B6" title="föö">foo</a></p>
[foo]
[foo]: /föö "föö"
<p><a href="/f%C3%B6%C3%B6" title="föö">foo</a></p>
实体和数字字符引用被视为文字 代码跨度和代码块中的文本:
不能使用实体和数字字符引用 代替 CommonMark 中表示结构的符号 文件。
我们可以将文档视为一系列 块 ——结构元素,如段落、块 引用、列表、标题、规则和代码块。一些块(例如 块引用和列表项)包含其他块;其他人(比如 标题和段落)包含 内联 内容 - 文本, 链接、强调文本、图像、代码跨度等。
块结构的指标始终优先于指标 的内联结构。因此,例如,以下是一个列表 两项,而不是其中一项包含代码范围的列表:
这意味着解析可以分两步进行:首先,块 可以辨别文档的结构;第二,里面的文字行 段落、标题和其他块结构可以被解析为内联 结构。第二步需要有关链接引用的信息 仅在第一个定义的末尾可用的定义 步。请注意,第一步需要按顺序处理行, 但第二个可以并行化,因为内联解析 一个块元素不会影响任何其他块元素的内联解析。
我们可以将块分为两种类型: 集装箱块 , 它可以包含其他块和 叶块 , 这是不能的。
本节描述了组成叶子块的不同类型 降价文档。
一行由最多三个缩进空格组成,后跟一个
三个或更多匹配的序列 -
, _
, 或者 *
字符,每个都跟随
可选地由任意数量的空格或制表符组成
主题休息 。
错误字符:
字符数不足:
最多允许三个空格的缩进:
四个空格的缩进太多了:
可以使用三个以上的字符:
字符之间允许有空格和制表符:
末尾允许使用空格和制表符:
但是,该行中不能出现其他字符:
要求除空格或制表符之外的所有字符都相同。 所以,这不是一个主题中断:
主题休息前后不需要空行:
主题中断可以打断一个段落:
如果一条虚线满足上述条件 的下划线 主题中断也可以解释为固定文本 标题 , 解释为 setext 标题 优先。因此,例如, 这是一个固定文本标题,而不是后面有主题中断的段落:
当主题休息和列表项都可以时 对一行的解释,主题中断优先:
如果您想在列表项中进行主题中断,请使用不同的项目符号:
标题 ATX
由一串字符组成,解析为内联内容,位于
1-6 未转义的开头序列 #
字符和可选的
任意数量的未转义的结束序列 #
人物。
开场顺序为 #
字符后必须跟空格或制表符,或者
到行尾。可选的关闭顺序 #
s 之前必须是
空格或制表符,并且后面只能跟空格或制表符。开幕
#
字符前面最多可以有三个缩进空格。原始的
标题内容被去除前导和尾随空格或制表符
在被解析为内联内容之前。标题级别等于数字
的 #
开头序列中的字符。
简单标题:
# foo
## foo
### foo
#### foo
##### foo
###### foo
<h1>foo</h1>
<h2>foo</h2>
<h3>foo</h3>
<h4>foo</h4>
<h5>foo</h5>
<h6>foo</h6>
六个以上 #
字符不是标题:
之间至少需要一个空格或制表符 #
人物和
标题的内容,除非标题为空。请注意,许多
目前的实现不需要空间。然而,
需要空间
原始ATX实现 ,
它有助于防止以下内容被解析为
标题:
这不是标题,因为第一个 #
被转义:
内容被解析为内联:
解析内联内容时会忽略前导和尾随空格或制表符:
最多允许三个空格的缩进:
四个空格的缩进太多了:
结束序列 #
字符是可选的:
它不需要与开头序列的长度相同:
结束序列后允许使用空格或制表符:
一系列 #
其后除空格或制表符外的任何字符
不是结束序列,但算作内容的一部分
标题:
结束序列之前必须有空格或制表符:
反斜杠转义 #
字符不算作一部分
关闭顺序:
ATX 标题不需要与周围的内容用空格分隔 行,并且它们可以打断段落:
ATX 标题可以为空:
一个 settext 标题 由一个或多个 不被空行打断的文本行,其中第一行不被空行打断 有超过 3 个缩进空间,后面是 下划线 设置文本标题 。文本行必须是这样的 如果他们后面没有下划线的 setext 标题, 它们将被解释为一个段落:它们不能 可解释为 代码围栏 、 ATX 标题 、 块引用 、 主题休息 、 列表项 ,或 HTML 块 。
settext标题 下划线 是一系列
=
字符或序列 -
字符数,最多不超过3个
缩进空格和任意数量的尾随空格或制表符。
如果满足以下条件,则该标题为 1 级标题: =
字符用于
setext标题 下划线 和 2 级标题 if -
使用字符。标题内容即为结果
将前面的文本行解析为 CommonMark 内联
内容。
一般来说,固定文本标题之前或之后不需要 空行。然而,它不能打断一个段落,所以当 setext 标题位于段落之后,段落之间需要一个空行 他们。
简单的例子:
Foo *bar*
=========
Foo *bar*
---------
<h1>Foo <em>bar</em></h1>
<h2>Foo <em>bar</em></h2>
标头的内容可能跨越一行以上:
内容是解析原始标题的结果 内容作为内联。标题的原始内容由以下内容组成 连接各行并删除开头和结尾 空格或制表符。
下划线可以是任意长度:
标题内容前面最多可以有三个缩进空格,并且 不需要与下划线对齐:
四个空格的缩进太多了:
setext 标题下划线前面最多可以有三个空格 缩进,并且可能有尾随空格或制表符:
四个空格的缩进太多了:
setext 标题下划线不能包含内部空格或制表符:
内容行中的尾随空格或制表符不会导致硬换行:
末尾也没有反斜杠:
由于块结构的指标优先于 内联结构的指示符,以下是setext标题:
`Foo
----
`
<a title="a lot
---
of dashes"/>
<h2>`Foo</h2>
<p>`</p>
<h2><a title="a lot</h2>
<p>of dashes"/></p>
setext 标题下划线不能是 惰性延续 行: 列表项或块引用中的
段落与后续段落之间需要有一个空行 setext 标题,否则该段落将成为一部分 标题内容:
但一般情况下前后不需要空行 设置文本标题:
Setext 标题不能为空:
Setext 标题文本行不得被解释为块 段落以外的结构。所以,虚线 在这些例子中被解释为主题中断:
如果你想要一个标题 > foo
作为其文字文本,您可以
使用反斜杠转义:
兼容性说明: 大多数现有 Markdown 实现 不允许 setext 标题的文本跨越多行。 但对于如何解读却没有达成共识
Foo
bar
---
baz
人们可以找到四种不同的解释:
我们发现解释 4 最自然,并且解释 4 通过允许增加 CommonMark 的表达能力 多行标题。想要解释1的作者可以 在第一段后添加一个空行:
想要解释 2 的作者可以在周围添加空行 主题休息,
或使用不能算作 固定文本标题 的主题中断 下划线 ,例如
想要解释 3 的作者可以使用反斜杠转义:
一个 缩进的代码块 由一个或多个组成 缩进块 由空行分隔的 。 是 缩进块 一系列非空行, 每个前面都有四个或更多的缩进空间。代码内容 块是行的文字内容,包括尾随 行结尾 ,减去四个缩进空格。 缩进的代码块没有 信息字符串 。
缩进的代码块不能打断一个段落,因此必须有 段落和后面的缩进代码块之间的空行。 (但是,代码块和后面的代码块之间不需要空行 段落。)
如果缩进的解释之间存在任何歧义 作为代码块并指示材料属于 列表 item ,列表项解释优先:
代码块的内容是文字文本,不会被解析 作为降价:
这里我们有三个由空行分隔的块:
任何超过四个缩进空格的初始空格或制表符都将包含在 内容,即使在内部空白行中:
缩进的代码块不能中断段落。 (这 允许悬挂缩进等。)
但是,任何缩进空间少于四个的非空行都会结束 立即执行代码块。所以一个段落可能会立即出现 缩进代码后:
缩进代码可以紧接在其他类型的之前和之后出现 块:
# Heading
foo
Heading
------
foo
----
<h1>Heading</h1>
<pre><code>foo
</code></pre>
<h2>Heading</h2>
<pre><code>foo
</code></pre>
<hr />
第一行前面可以有四个以上的缩进空格:
缩进代码块之前或之后的空行 不包括在其中:
尾随空格或制表符包含在代码块的内容中:
代码 栅栏 是一个序列
至少三个连续的反引号字符( `
) 或者
波形符( ~
)。 (波形符和反引号不能混合使用。)
块 受围栏保护的代码
以代码围栏开始,前面最多有三个缩进空间。
带有开放代码围栏的行可以选择包含一些文本 遵循代码围栏;这是修剪了前导和尾随的 空格或制表符并称为 信息字符串 。如果 信息字符串 出现 在反引号栅栏之后,它不能包含任何反引号 人物。 (此限制的原因是否则 一些内联代码会被错误地解释为 受保护的代码块的开始。)
代码块的内容由所有后续行组成,直到 关闭 代码栅栏 与代码块类型相同的 以(反引号或波形符)开头,并且至少有同样多的反引号 或波形符作为起始代码栏。如果前导代码围栏是 前面有 N 个缩进空间,然后最多有 N 个缩进空间 从内容的每一行中删除(如果存在)。 (如果内容行不是 缩进,它保持不变。如果缩进N个空格或更少,则全部 压痕已被删除。)
结束代码栅栏之前最多可以有三个缩进空格,并且 后面可能只跟空格或制表符,这些都会被忽略。如果结束时 到达包含块(或文档)并且没有关闭代码围栏 已经找到,代码块包含了之后的所有行 打开代码围栏直到包含块的末尾(或 文档)。 (替代规范需要在 未找到关闭代码围栏的事件。但这使得解析 效率低得多,而且似乎没有真正的缺点 此处描述的行为。)
受隔离的代码块可能会中断一个段落,并且不需要 之前或之后的空行。
代码围栏的内容被视为文字文本,而不是被解析
作为内联。 的第一个单词 信息字符串 通常用于
指定代码示例的语言,并在 class
的属性 code
标签。然而,这个规范并没有强制要求任何
的特殊处理 对信息字符串 。
这是一个带有反引号的简单示例:
带波形符:
少于三个反引号是不够的:
结束码围栏必须使用与开始码相同的字符 栅栏:
关闭代码栅栏必须至少与打开栅栏一样长:
未关闭的代码块在文档末尾关闭 (或封闭的 块引用 或 列表项 ):
代码块可以将所有空行作为其内容:
代码块可以为空:
栅栏可以缩进。如果开口围栏是缩进的, 内容行将删除等效的开头缩进, 如果存在:
四个空格的缩进太多了:
封闭栅栏之前最多可以有三个缩进空间,并且它们的 缩进不需要与开口栅栏的缩进相匹配:
这不是封闭栅栏,因为它缩进了 4 个空格:
代码围栏(打开和关闭)不能包含内部空格或制表符:
围栏代码块可以打断段落,并且可以跟随 直接按段落,之间没有空行:
其他块也可以出现在受防护的代码块之前和之后 没有中间的空行:
。 信息字符串 可以在开放代码围栏之后提供
尽管这个规范没有强制要求任何特定的处理
信息字符串,第一个单词通常用于指定
代码块的语言。在 HTML 输出中,语言是
通常通过添加一个类来表示 code
元素组成
的 language-
接下来是语言名称。
```ruby
def foo(x)
return 3
end
```
<pre><code class="language-ruby">def foo(x)
return 3
end
</code></pre>
~~~~ ruby startline=3 $%@#$
def foo(x)
return 3
end
~~~~~~~
<pre><code class="language-ruby">def foo(x)
return 3
end
</code></pre>
信息字符串不能包含反引号: 反引号代码块的
波形符代码块的信息字符串 可以包含反引号和波形符:
关闭代码围栏不能有 信息字符串 :
是 HTML 块 一组经过处理的行 作为原始 HTML(并且不会在 HTML 输出中转义)。
有七种 HTML 块 ,可以通过它们来定义 开始和结束条件。该块以满足以下条件的行开始 开始条件 (最多三个可选的缩进空格之后)。 它以满足匹配条件的第一个后续行结束 结束条件 ,或文档的最后一行,或 块 容器 包含当前 HTML 的 块,如果没有遇到满足 结束条件的 行。如果 第一行满足 开始条件 和 结束 条件 条件 ,该块将只包含该行。
开始条件: 行以字符串开头 <pre
,
<script
, <style
, 或者 <textarea
(不区分大小写),后跟一个空格,
制表符、字符串 >
,或行尾。
结束条件: 行包含结束标记
</pre>
, </script>
, </style>
, 或者 </textarea>
(不区分大小写;它
不需要匹配开始标签)。
开始条件: 行以字符串开头 <!--
。
结束条件: 行包含字符串 -->
。
开始条件: 行以字符串开头 <?
。
结束条件: 行包含字符串 ?>
。
开始条件: 行以字符串开头 <!
后跟一个 ASCII 字母。
结束条件: 行包含该字符 >
。
开始条件: 行以字符串开头
<![CDATA[
。
结束条件: 行包含字符串 ]]>
。
开始条件: 行以字符串开头 <
或者 </
后跟字符串之一(不区分大小写) address
,
article
, aside
, base
, basefont
, blockquote
, body
,
caption
, center
, col
, colgroup
, dd
, details
, dialog
,
dir
, div
, dl
, dt
, fieldset
, figcaption
, figure
,
footer
, form
, frame
, frameset
,
h1
, h2
, h3
, h4
, h5
, h6
, head
, header
, hr
,
html
, iframe
, legend
, li
, link
, main
, menu
, menuitem
,
nav
, noframes
, ol
, optgroup
, option
, p
, param
,
search
, section
, summary
, table
, tbody
, td
,
tfoot
, th
, thead
, title
, tr
, track
, ul
,随后
由空格、制表符、行尾、字符串组成 >
, 或者
字符串 />
。
结束条件: 一行后面有一个 空行 。
开始条件: 行以完整的 开放标记 开始
( 除 使用 pre
, script
,
style
, 或者 textarea
) 或完整的 结束标签 ,
后跟零个或多个空格和制表符,最后是行尾。
结束条件: 一行后面有一个 空行 。
HTML 块将继续运行,直到它们被相应的块关闭为止。 结束条件 ,或文档或其他 容器 的最后一行 堵塞 。这意味着 HTML 中的 任何 HTML 块 否则可能被识别为启动条件的 将 被解析器忽略并按原样传递,无需更改 解析器的状态。
例如, <pre>
在由以下内容开始的 HTML 块中 <table>
不会影响
解析器状态;由于 HTML 块是由启动条件 6 启动的,因此
将在任何空行处结束。这可能会令人惊讶:
<table><tr><td>
<pre>
**Hello**,
_world_.
</pre>
</td></tr></table>
<table><tr><td>
<pre>
**Hello**,
<p><em>world</em>.
</pre></p>
</td></tr></table>
在本例中,HTML 块以空行终止 — **Hello**
文本保持逐字记录——并且常规解析继续,带有一个段落,
强调 world
以及内联和块 HTML 跟随。
除类型 7 之外的所有类型的 HTML 块 都可能会中断 一个段落。类型 7 的块不能中断段落。 (此限制旨在防止不必要的解释 包装段落内的长标签作为起始 HTML 块。)
下面是一些简单的例子。以下是一些基本的 HTML 块 类型6:
<table>
<tr>
<td>
hi
</td>
</tr>
</table>
okay.
<table>
<tr>
<td>
hi
</td>
</tr>
</table>
<p>okay.</p>
块也可以以结束标记开头:
这里我们有两个 HTML 块,它们之间有一个 Markdown 段落:
第一行的标签可以是部分的,只要 因为它在有空格的地方被分割:
开放标签不需要关闭:
部分标签甚至不需要完成(垃圾 输入,垃圾输出):
初始标签甚至不需要是有效的 标签,只要它开头如下:
在类型 6 块中,初始标记不必位于一行 本身:
直到下一个空行或文档末尾的所有内容 包含在 HTML 块中。所以,在下面的 例如,看起来像 Markdown 代码块 实际上是 HTML 块的一部分,一直持续到空白 行或到达文档末尾:
开始 HTML 块 标签 使用不在 以下位置的 (6) 中的块级标签列表,您必须将标签放在 本身在第一行(并且必须完整):
在类型 7 块中, 标签名称 可以是任何内容:
这些规则旨在让我们能够使用以下标签:
可以用作块级或内联级标记。
这 <del>
标签就是一个很好的例子。我们可以围绕内容
<del>
以三种不同的方式进行标记。在这种情况下,我们得到一个原始的
HTML 块,因为 <del>
标签本身在一行上:
在本例中,我们得到一个原始 HTML 块,其中仅包含
这 <del>
标签(因为它以以下空白结尾
线)。因此内容被解释为 CommonMark:
最后,在这种情况下, <del>
标签被解释
作为 原始 HTML 内的 CommonMark 段落 。 (因为
标签本身不在一行,我们得到内联 HTML
而不是 HTML 块 。)
旨在包含文字内容的 HTML 标签
( pre
, script
, style
, textarea
)、评论、处理说明、
和声明的处理方式有所不同。
这些块不是以第一个空行结束,而是
end 位于包含相应结束标记的第一行。
因此,这些块可以包含空行:
预标记(类型 1):
<pre language="haskell"><code>
import Text.HTML.TagSoup
main :: IO ()
main = print $ parseTags tags
</code></pre>
okay
<pre language="haskell"><code>
import Text.HTML.TagSoup
main :: IO ()
main = print $ parseTags tags
</code></pre>
<p>okay</p>
脚本标签(类型 1):
<script type="text/javascript">
// JavaScript example
document.getElementById("demo").innerHTML = "Hello JavaScript!";
</script>
okay
<script type="text/javascript">
// JavaScript example
document.getElementById("demo").innerHTML = "Hello JavaScript!";
</script>
<p>okay</p>
文本区域标签(类型 1):
样式标签(类型 1):
<style
type="text/css">
h1 {color:red;}
p {color:blue;}
</style>
okay
<style
type="text/css">
h1 {color:red;}
p {color:blue;}
</style>
<p>okay</p>
如果没有匹配的结束标记,则该块将在 文档末尾(或封闭的 块引用 或 列表项 ):
结束标记可以与开始标记出现在同一行:
请注意,最后一行上的任何内容 结束标签将包含在 HTML 块 中:
评论(类型 2):
处理指令(类型3):
声明(类型 4):
CDATA(类型 5):
<![CDATA[
function matchwo(a,b)
{
if (a < b && a < 0) then {
return 1;
} else {
return 0;
}
}
]]>
okay
<![CDATA[
function matchwo(a,b)
{
if (a < b && a < 0) then {
return 1;
} else {
return 0;
}
}
]]>
<p>okay</p>
开始标记前面最多可以有三个缩进空格,但不能 四:
类型 1-6 的 HTML 块可以打断一个段落,并且不需要 前面有一个空行。
但是,除了结尾处之外,还需要一个以下空行 一个文档,除了 上述 类型 1-5 的块:
类型 7 的 HTML 块不能中断段落:
该规则与 John Gruber 的原始 Markdown 语法不同 规范,其中说:
唯一的限制是块级 HTML 元素 - 例如
<div>
,<table>
,<pre>
,<p>
等——必须与 用空行包围内容,以及开始和结束标签 块不应缩进空格或制表符。
在某些方面,格鲁伯的规则比给定的规则更具限制性 这里:
大多数 Markdown 实现(包括 Gruber 自己的一些实现)都没有 尊重所有这些限制。
然而,在一个方面,格鲁伯的规则更加自由 比这里给出的,因为它允许空行出现在里面 HTML 块。这里禁止它们有两个原因。 首先,它消除了解析平衡标签的需要,即 昂贵并且可能需要从文档末尾回溯 如果没有找到匹配的结束标记。其次,它提供了一个非常简单的 以及在 HTML 标签中包含 Markdown 内容的灵活方式: 只需使用空行将 Markdown 与 HTML 分开:
比较:
一些 Markdown 实现采用了以下约定
如果开放标签有,则将标签内的内容解释为文本
属性 markdown=1
。上面给出的规则似乎更简单
实现相同表现力的更优雅的方式,这也是
解析起来要简单得多。
主要的潜在缺点是无法再粘贴 HTML 块以 100% 的可靠性写入 Markdown 文档。然而, 在大多数情况下, 这可以正常工作,因为中的空白行 HTML 后面通常跟着 HTML 块标记。例如:
但是,如果内部标签缩进,就会出现问题 并 用空格分隔,这样它们将被解释为 缩进的代码块:
<table>
<tr>
<td>
Hi
</td>
</tr>
</table>
<table>
<tr>
<pre><code><td>
Hi
</td>
</code></pre>
</tr>
</table>
幸运的是,空行通常不是必需的,可以
已删除。例外是在里面 <pre>
标签,但如上所述
上面 ,原始 HTML 块开头为 <pre>
可以 包含空行。
链接 参考定义
由一个 链接标签 组成,前面可以选择最多三个空格
缩进,后跟
用冒号 ( :
)、可选空格或制表符(最多包含一个
行尾 ), 链接目标 ,
可选空格或制表符(最多包括一个
行结尾 ) 和可选 链接
title ,如果存在则必须将其分开
通过空格或制表符从 链接目标 开始。
不能再出现任何字符。
链接 参考定义 不对应于文档的结构元素。相反,它 中使用的标签 定义可在参考链接 参考样式 图像 以及文档其他地方的 。关联 参考定义 可以位于使用的链接之前或之后 他们。
[Foo*bar\]]:my_(url) 'title (with parens)'
[Foo*bar\]]
<p><a href="my_(url)" title="title (with parens)">Foo*bar]</a></p>
[Foo bar]:
<my url>
'title'
[Foo bar]
<p><a href="my%20url" title="title">Foo bar</a></p>
标题可以跨越多行:
[foo]: /url '
title
line1
line2
'
[foo]
<p><a href="/url" title="
title
line1
line2
">foo</a></p>
但是,它可能不包含 空行 :
[foo]: /url 'title
with blank line'
[foo]
<p>[foo]: /url 'title</p>
<p>with blank line'</p>
<p>[foo]</p>
标题可以省略:
链接目标不能省略:
但是,可以使用指定空链接目的地 尖括号:
标题必须与链接目标分隔开 空格或制表符:
标题和目标都可以包含反斜杠转义符 和文字反斜杠:
[foo]: /url\bar\*baz "foo\"bar\baz"
[foo]
<p><a href="/url%5Cbar*baz" title="foo"bar\baz">foo</a></p>
链接可以位于其相应的定义之前:
如果有多个匹配的定义,则第一个为 优先级:
部分所述 正如链接 ,标签的匹配是 不区分大小写(参见 matches )。
某物是否是 链接引用定义 是 与它定义的链接引用是否无关 文档中使用。因此,例如,以下 文档仅包含链接引用定义,并且 无可见内容:
这是另一个:
这不是链接引用定义,因为有 标题后除空格或制表符之外的字符:
这是一个链接参考定义,但它没有标题:
这不是链接引用定义,因为它是缩进的 四个空格:
[foo]: /url "title"
[foo]
<pre><code>[foo]: /url "title"
</code></pre>
<p>[foo]</p>
这不是链接引用定义,因为它出现在内部 一个代码块:
链接 引用定义 不能中断段落。
但是,它可以直接跟随其他块元素,例如标题 和主题中断,并且后面不需要有空行。
# [Foo]
[foo]: /url
> bar
<h1><a href="/url">Foo</a></h1>
<blockquote>
<p>bar</p>
</blockquote>
几个 链接参考定义 可以一个接一个地出现,中间没有空行。
[foo]: /foo-url "foo"
[bar]: /bar-url
"bar"
[baz]: /baz-url
[foo],
[bar],
[baz]
<p><a href="/foo-url" title="foo">foo</a>,
<a href="/bar-url" title="bar">bar</a>,
<a href="/baz-url">baz</a></p>
链接引用定义 可能发生 在块容器内,例如列表和块引用。他们 影响整个文档,而不仅仅是它们所在的容器 定义为:
不能被解释为其他的非空行序列 各种块组成一个 段落 。 该段落的内容是解析的结果 段落的原始内容作为内联。该段落的原始内容 通过连接行并删除初始和最终形成 空格或制表符。
一个简单的例子,有两段:
段落可以包含多行,但不能包含空行:
段落之间的多个空行没有效果:
跳过前导空格或制表符:
第一行之后的行可以缩进任意数量,因为缩进 代码块不能打断段落。
但是,第一行前面最多可以有三个缩进空间。 四个空格的缩进太多了:
最后的空格或制表符在内联解析之前被删除,因此一个段落 以两个或多个空格结尾的不会以 硬线 结尾 休息 :
空行将 块级元素之间的 被忽略, 除了它们在确定列表 是否 是 紧 还是 松 。
文档开头和结尾的空白行也将被忽略。
是 容器块 具有其他块的块 块作为其内容。有两种基本类型的容器块: 块引用 和 列表项 。 列表 的元容器 是列表项 。
我们递归地定义容器块的语法。将军 定义的形式为:
如果 X 是块序列,则结果 以这样那样的方式转换 X 是类型 Y 的容器 以这些块作为其内容。
因此,我们通过解释来解释什么算作块引用或列表项 如何 生成 从其内容 这些内容。这应该足够了 定义语法,尽管它没有给出 解析 的秘诀 这些构造。 (下面标题为“菜谱”的部分提供了一个食谱 解析策略 。)
标记 块引号 ,
前面可以选择最多三个缩进空格,
由 (a) 字符组成 >
连同以下空间
缩进,或 (b) 单个字符 >
后面没有空格
缩进。
以下规则定义 块引号 :
基本案例。 如果一串行 Ls 构成一个序列 块 Bs 的结果 ,然后是在前面添加块引用 标记 中每行的开头 到Ls 是 块引用 包含 Bs 的 。
懒惰。 如果一串行 Ls 构成一个 块 引用 内容 Bs ,然后删除的结果 初始 块引用标记 来自一个或的 更多行,其中除空格或制表符之外的下一个字符 块引用标记 是 段落延续 text 块引用 是以Bs 为内容的 。 段落延续文本 是文本 将被解析为段落内容的一部分,但确实 不出现在段落的开头。
连续性。 一个文档不能包含两个 块 引号 连续 ,除非它们之间有空行 。
其他任何内容都不能算作 块引用 。
这是一个简单的例子:
后面的空格或制表符 >
可以省略字符:
这 >
字符前面最多可以有三个缩进空格:
四个空格的缩进太多了:
惰性条款允许我们省略 >
前
段落延续文字 :
块引用可以包含一些惰性引用和一些非惰性引用 续行:
懒惰仅适用于本来是延续的行
段落前面是否带有 块引号标记 。
例如, >
第二行不能省略
> foo
> ---
不改变含义:
同样,如果我们省略 >
在第二行
> - foo
> - bar
那么块引用在第一行之后结束:
> - foo
- bar
<blockquote>
<ul>
<li>foo</li>
</ul>
</blockquote>
<ul>
<li>bar</li>
</ul>
出于同样的原因,我们也不能忽略 >
在...前面
缩进或围栏代码块的后续行:
> foo
bar
<blockquote>
<pre><code>foo
</code></pre>
</blockquote>
<pre><code>bar
</code></pre>
> ```
foo
```
<blockquote>
<pre><code></code></pre>
</blockquote>
<p>foo</p>
<pre><code></code></pre>
请注意,在以下情况下,我们有一个 惰性的 续行 :
要了解原因,请注意
> foo
> - bar
这 - bar
缩进太远而无法开始列表,并且不能
是缩进的代码块,因为缩进的代码块不能
中断段落,因此是 段落延续文本 。
块引用可以为空:
块引用可以有开头或结尾的空行:
空行始终分隔块引号:
(大多数当前的 Markdown 实现,包括 John Gruber 的
原来的 Markdown.pl
,将将此示例解析为单块引用
有两个段落。但似乎还是让作者自己决定比较好
是否需要两个块引号或一个。)
连续性意味着如果我们将这些块引用放在一起, 我们得到一个单块引用:
要获得包含两个段落的块引用,请使用:
块引号可以打断段落:
一般情况下,块前后不需要空行 引号:
> aaa
***
> bbb
<blockquote>
<p>aaa</p>
</blockquote>
<hr />
<blockquote>
<p>bbb</p>
</blockquote>
不过因为懒,中间需要空行 块引用和以下段落:
这是惰性规则的结果,任何数字
初始的 >
a 的连续行上的 s 可以省略
嵌套块引用:
> > > foo
bar
<blockquote>
<blockquote>
<blockquote>
<p>foo
bar</p>
</blockquote>
</blockquote>
</blockquote>
>>> foo
> bar
>>baz
<blockquote>
<blockquote>
<blockquote>
<p>foo
bar
baz</p>
</blockquote>
</blockquote>
</blockquote>
当在块引用中包含缩进的代码块时,
请记住, 块引用标记 包括
两者都 >
以及后面的缩进空间。所以 五个空格 需要
之后 >
:
> code
> not code
<blockquote>
<pre><code>code
</code></pre>
</blockquote>
<blockquote>
<p>not code</p>
</blockquote>
标记 项目符号列表
是一个 -
, +
, 或者 *
特点。
有序 列表标记
是 1-9 个阿拉伯数字的序列 ( 0-9
),后跟一个
.
字符或一个 )
特点。 (长度的原因
限制是 10 位数字后我们开始看到整数溢出
在某些浏览器中。)
以下规则定义 列表项 :
基本案例。 如果一系列线 Ls 构成一个序列 阻止 B 以空格或制表符以外的字符开头的 ,并且M 是 的列表标记, 宽度为W 后跟 1 ≤ N ≤ 4 个缩进空间, 添加到第一行的结果 然后将M 和后面的空格 Ls ,并将 的后续行缩进 Ls 个空格 W + N ,是 作为其内容的列表项 以Bs 。列表项的类型 (项目符号或有序)由其列表标记的类型确定。 如果列表项是有序的,那么它也会被分配一个开始 数字,基于有序列表标记。
例外情况:
例如,令 Ls 为线
A paragraph
with two lines.
indented code
> A block quote.
<p>A paragraph
with two lines.</p>
<pre><code>indented code
</code></pre>
<blockquote>
<p>A block quote.</p>
</blockquote>
并让 M 成为标记 1.
,并且 N = 2。然后规则#1 说
以下是一个起始编号为 1 的有序列表项,
的内容相同 和Ls :
1. A paragraph
with two lines.
indented code
> A block quote.
<ol>
<li>
<p>A paragraph
with two lines.</p>
<pre><code>indented code
</code></pre>
<blockquote>
<p>A block quote.</p>
</blockquote>
</li>
</ol>
最需要注意的是, 列表标记后面的文本决定缩进量 在列表项的后续块中需要。如果列表 标记占用两个缩进空间,并且之间有三个空格 列表标记和除空格或制表符之外的下一个字符,然后阻塞 必须缩进五个空格才能落入列表中 物品。
以下是一些示例,显示内容必须缩进多远 放在列表项下:
人们很容易从列的角度来思考这一点:延续 块必须至少缩进到除 列表标记后的空格或制表符。然而,这并不完全正确。 列表标记后面的缩进空格决定了相对的程度 需要缩进。该缩进到达哪一列取决于 列表项如何嵌入到其他结构中,如下所示 这个例子:
> > 1. one
>>
>> two
<blockquote>
<blockquote>
<ol>
<li>
<p>one</p>
<p>two</p>
</li>
</ol>
</blockquote>
</blockquote>
这里 two
与列表标记出现在同一列中 1.
,
但实际上包含在列表项中,因为有
最后一个包含块引用标记后有足够的缩进。
反之亦然。在下面的例子中,单词 two
出现在列表项初始文本的右侧很远的地方, one
, 但
它不被视为列表项的一部分,因为它没有缩进
距离块引用标记足够远:
>>- one
>>
> > two
<blockquote>
<blockquote>
<ul>
<li>one</li>
</ul>
<p>two</p>
</blockquote>
</blockquote>
请注意,列表标记和列表标记之间至少需要一个空格或制表符。 任何以下内容,因此这些不是列表项:
列表项可能包含由多个分隔的块 一个空行。
列表项可以包含任何类型的块:
1. foo
```
bar
```
baz
> bam
<ol>
<li>
<p>foo</p>
<pre><code>bar
</code></pre>
<p>baz</p>
<blockquote>
<p>bam</p>
</blockquote>
</li>
</ol>
包含缩进代码块的列表项将保留 代码块中的空行逐字。
请注意,有序列表的起始编号必须为九位或更少:
起始编号可以以 0 开头:
起始编号不能为负数:
缩进的代码块前面必须有四个缩进空格 超出列表项中包含文本的区域的边缘。 在以下情况下为 6 个空格:
在本例中为 11 个空格:
如果 列表项中的第一个 块是缩进代码块, 然后根据规则#2,内容前面必须有 一个 缩进空格 在列表标记之后:
indented code
paragraph
more code
<pre><code>indented code
</code></pre>
<p>paragraph</p>
<pre><code>more code
</code></pre>
1. indented code
paragraph
more code
<ol>
<li>
<pre><code>indented code
</code></pre>
<p>paragraph</p>
<pre><code>more code
</code></pre>
</li>
</ol>
请注意,额外的缩进空间被解释为空格 代码块内:
1. indented code
paragraph
more code
<ol>
<li>
<pre><code> indented code
</code></pre>
<p>paragraph</p>
<pre><code>more code
</code></pre>
</li>
</ol>
请注意,规则 #1 和规则 #2 仅适用于两种情况: (a) 情况 其中要包含在列表项中的行以 空格或制表符以外的字符,以及 (b) 的情况 它们以缩进代码开头 堵塞。在如下情况下,第一个块开头为 三个空格的缩进,规则不允许我们通过以下方式形成列表项 缩进整个内容并在前面添加一个列表标记:
这不是一个重要的限制,因为当一个块前面最多有 三个空格的缩进,缩进可以随时删除,无需 解释的改变,允许应用规则#1。所以,在 上述案例:
以下是一些以空行开头但不为空的列表项:
-
foo
-
```
bar
```
-
baz
<ul>
<li>foo</li>
<li>
<pre><code>bar
</code></pre>
</li>
<li>
<pre><code>baz
</code></pre>
</li>
</ul>
当列表项以空行开头时,空格数 遵循列表标记不会更改所需的缩进:
列表项最多可以以一个空行开始。
在下面的示例中, foo
不属于列表的一部分
物品:
这是一个空的项目符号列表项:
后面是否有空格或制表符并不重要 列表标记 :
这是一个空的有序列表项:
列表可以以空列表项开始或结束:
但是,空列表项不能中断段落:
缩进一个空格:
1. A paragraph
with two lines.
indented code
> A block quote.
<ol>
<li>
<p>A paragraph
with two lines.</p>
<pre><code>indented code
</code></pre>
<blockquote>
<p>A block quote.</p>
</blockquote>
</li>
</ol>
缩进两个空格:
1. A paragraph
with two lines.
indented code
> A block quote.
<ol>
<li>
<p>A paragraph
with two lines.</p>
<pre><code>indented code
</code></pre>
<blockquote>
<p>A block quote.</p>
</blockquote>
</li>
</ol>
缩进三个空格:
1. A paragraph
with two lines.
indented code
> A block quote.
<ol>
<li>
<p>A paragraph
with two lines.</p>
<pre><code>indented code
</code></pre>
<blockquote>
<p>A block quote.</p>
</blockquote>
</li>
</ol>
四个空格缩进给出一个代码块:
1. A paragraph
with two lines.
indented code
> A block quote.
<pre><code>1. A paragraph
with two lines.
indented code
> A block quote.
</code></pre>
这是一个带有 惰性连续线 的示例:
1. A paragraph
with two lines.
indented code
> A block quote.
<ol>
<li>
<p>A paragraph
with two lines.</p>
<pre><code>indented code
</code></pre>
<blockquote>
<p>A block quote.</p>
</blockquote>
</li>
</ol>
可以部分删除缩进:
这些示例展示了惰性如何在嵌套结构中发挥作用:
> 1. > Blockquote
continued here.
<blockquote>
<ol>
<li>
<blockquote>
<p>Blockquote
continued here.</p>
</blockquote>
</li>
</ol>
</blockquote>
> 1. > Blockquote
> continued here.
<blockquote>
<ol>
<li>
<blockquote>
<p>Blockquote
continued here.</p>
</blockquote>
</li>
</ol>
</blockquote>
子列表的规则遵循一般规则 多于 。子列表必须缩进相同的数字 段落需要的缩进空间才能被包含在内 在列表项中。
因此,在这种情况下我们需要两个空格缩进:
- foo
- bar
- baz
- boo
<ul>
<li>foo
<ul>
<li>bar
<ul>
<li>baz
<ul>
<li>boo</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
一个还不够:
这里我们需要四个,因为列表标记更宽:
三个还不够:
列表可以是列表项中的第一个块:
1. - 2. foo
<ol>
<li>
<ul>
<li>
<ol start="2">
<li>foo</li>
</ol>
</li>
</ul>
</li>
</ol>
列表项可以包含标题:
John Gruber 的 Markdown 规范对列表项做了以下说明:
“列表标记通常从左边距开始,但可能会缩进 最多三个空格。列表标记后面必须跟一个或多个 空格或制表符。”
“为了让列表看起来更漂亮,你可以用悬挂缩进来包裹项目...... 但如果你不愿意,那就没必要。”
“列表项可能由多个段落组成。随后的每一个 列表项中的段落必须缩进 4 个空格或 1 个空格 标签。”
“如果你缩进后续段落的每一行,看起来会很好, 但在这里,Markdown 会让你变得懒惰。”
“要将块引用放入列表项中,块引用的 >
分隔符需要缩进。”
“要将代码块放入列表项中,需要将该代码块 缩进两次——8 个空格或两个制表符。”
这些规则指定列表项下的段落必须缩进 四个空格(大概是从左边距开始,而不是从开始处开始) 列表标记,但这没有说),以及列表项下的代码 必须缩进八个空格而不是通常的四个空格。他们还说 块引用必须缩进,但不缩进多少;然而, 给出的示例有四个空格缩进。虽然什么也没说 对于其他类型的块级内容,这当然是合理的 推断 所有 列表项下的 块元素,包括其他 列表,必须缩进四个空格。这一原则被称为 四空间规则 。
四空间规则是明确且有原则的,如果参考
执行 Markdown.pl
跟随它,它可能会
成为标准。然而, Markdown.pl
允许的段落和
子列表仅以两个空格缩进开头,至少在
外层。更糟糕的是,它的行为不一致:一个子列表
外层列表需要两个空格缩进,但它的子列表
子列表需要三个空格。那么,不同的情况也就不足为奇了
Markdown 的实现制定了非常不同的规则
确定列表项下的内容。 (Pandoc 和 python-Markdown,
例如,坚持格鲁伯的语法描述和四空格
规则、折扣、红毯、标记、PHP Markdown 等
已关注 Markdown.pl
的行为更接近。)
不幸的是,考虑到实现之间的差异,有
无法给出保证不会的列表项的规格
破坏任何现有文档。然而,这里给出的规格应该
正确处理使用四空格规则或
越宽容 Markdown.pl
行为,只要它们被列出
以人类自然阅读的方式。
这里的策略是让列表标记的宽度和缩进 确定块落入列表所需的缩进 项,而不是具有固定且任意的数量。笔者可以 将列表项的主体视为一个缩进到 足够适合列表标记(以及列表上的任何缩进 标记)。 (惰性规则#5,然后允许连续行 如果需要,可以不缩进。)
我们声称,这条规则优于任何需要固定水平的规则 从页边距缩进。四空格规则很明确,但是 不自然的。这是相当不直观的
- foo
bar
- baz
应该被解析为两个列表,中间有一个段落,
<ul>
<li>foo</li>
</ul>
<p>bar</p>
<ul>
<li>baz</li>
</ul>
正如四空间规则所要求的,而不是单个列表,
<ul>
<li>
<p>foo</p>
<p>bar</p>
<ul>
<li>baz</li>
</ul>
</li>
</ul>
四个空间的选择是任意的。可以学习,但这是 不太可能被猜到,而且它经常让初学者绊倒。
采用两格规则会有帮助吗?问题是这样的
一条规则,以及允许最多三个缩进空间的规则
缩进 小于 初始列表标记,允许
要包含在列表项中的原始列表标记。例如,
Markdown.pl
解析
- one
two
作为单个列表项, two
一个延续段落:
<ul>
<li>
<p>one</p>
<p>two</p>
</li>
</ul>
和类似地
> - one
>
> two
作为
<blockquote>
<ul>
<li>
<p>one</p>
<p>two</p>
</li>
</ul>
</blockquote>
这是极其不直观的。
我们可以不要求从边距固定缩进,而是要求
列表标记的固定缩进(例如,两个空格,甚至一个空格)(
本身可以缩进)。该提案将消除最后一个异常
讨论过。与上面提供的规范不同,它会计算以下内容
作为带有子段落的列表项,即使该段落 bar
没有缩进到第一段 foo
:
10. foo
bar
可以说这段文字读起来确实像一个列表项 bar
作为一个小段,
这可能有利于该提案。然而,该提案缩进
代码必须在列表标记后缩进六个空格。还有这个
会破坏很多现有的 Markdown,其模式如下:
1. foo
indented code
其中代码缩进八个空格。相比之下,上面的规范将
按预期解析此文本,因为测量了代码块的缩进
从一开始 foo
。
的列表项 需要特殊处理的一种情况是开始 带有缩进代码。在这种情况下需要多少缩进,因为 我们没有“第一段”来衡量?规则#2 简单地规定 在这种情况下,我们需要从列表标记处缩进一个空格 (然后是缩进代码的正常四个空格)。这将匹配 在列表标记加上其初始缩进的情况下的四空格规则 需要四个空格(常见情况),但在其他情况下会有所不同。
列表 序列 是一个或多个的 列出 相同类型的 项目。清单项目 可以用任意数量的空行分隔。
两个列表项 属于同一类型
开头 列表标记 如果它们以相同类型的 。
两个列表标记是
相同类型,如果 (a) 它们是使用相同字符的项目符号列表标记
( -
, +
, 或者 *
) 或 (b) 它们是具有相同顺序的列表编号
分隔符(或者 .
或者 )
)。
列表是一个 有序列表 如果其组成列表项开头为 有序列表标记 ,以及 项目符号列表 (如果其组成列表) 项目以 项目符号列表标记 开头。
编号 起始 的数量 有序列表 由列表数量决定 它的初始列表项。后续列表项的数量是 被忽视。
该列表是 松散的 如果列表中有任何组成部分,则
列表项由空行分隔,或者如果其任何组成部分
列表项直接包含两个带空行的块级元素
他们之间。否则,名单就很 紧张了 。
(HTML 输出的区别在于松散列表中的段落是
包裹在 <p>
标签,而紧凑列表中的段落则没有。)
更改项目符号或有序列表分隔符会启动一个新列表:
1. foo
2. bar
3) baz
<ol>
<li>foo</li>
<li>bar</li>
</ol>
<ol start="3">
<li>baz</li>
</ol>
在 CommonMark 中,列表可以打断段落。那是, 不需要空行来将段落与后面的段落分开 列表:
Markdown.pl
不允许这样做,因为担心触发列表
通过硬包裹行中的数字:
The number of windows in my house is
14. The number of doors is 6.
但奇怪的是, Markdown.pl
确实 允许块引用
打断一个段落,即使同样的考虑可能
申请。
在 CommonMark 中,我们确实允许列表打断段落,例如 有两个原因。首先,这对于人们来说是自然的且并不罕见 启动没有空行的列表:
I need to buy
- new shoes
- a coat
- a plane ticket
其次,我们被吸引
统一原则 : 如果一段文本有一定的 意思是,当放入一个 容器块(例如列表项或块引用)。
的规范 (事实上,列表项 和 块引用 预设 这个原则。)这个原则意味着如果
* I need to buy
- new shoes
- a coat
- a plane ticket
是一个列表项,其中包含一个段落,后跟一个嵌套子列表,
正如所有 Markdown 实现都同意的那样(尽管段落
可以在没有 <p>
标签,因为列表很“紧”),
然后
I need to buy
- new shoes
- a coat
- a plane ticket
其本身应该是一个段落,后面跟着一个嵌套子列表。
由于 Markdown 实践已成熟,允许列表 打断列表项内的段落, 原理 一致性 要求我们允许这个外部列表项为 出色地。 ( 重构文本 采用不同的方法,要求列表前有空行 甚至在其他列表项中。)
为了解决段落中不需要的列表的问题
硬包装数字,我们只允许以以下开头的列表 1
到
打断段落。因此,
The number of windows in my house is
14. The number of doors is 6.
<p>The number of windows in my house is
14. The number of doors is 6.</p>
在类似的情况下,我们仍然可能会得到意想不到的结果
The number of windows in my house is
1. The number of doors is 6.
<p>The number of windows in my house is</p>
<ol>
<li>The number of doors is 6.</li>
</ol>
但这条规则应该可以防止大多数虚假列表捕获。
项目之间可以有任意数量的空行:
- foo
- bar
- baz
<ul>
<li>
<p>foo</p>
</li>
<li>
<p>bar</p>
</li>
<li>
<p>baz</p>
</li>
</ul>
- foo
- bar
- baz
bim
<ul>
<li>foo
<ul>
<li>bar
<ul>
<li>
<p>baz</p>
<p>bim</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
分隔相同类型的连续列表,或分隔 来自缩进代码块的列表,否则将被解析 作为最终列表项的子段落,您可以插入空白 HTML 评论:
- foo
- bar
<!-- -->
- baz
- bim
<ul>
<li>foo</li>
<li>bar</li>
</ul>
<!-- -->
<ul>
<li>baz</li>
<li>bim</li>
</ul>
- foo
notcode
- foo
<!-- -->
code
<ul>
<li>
<p>foo</p>
<p>notcode</p>
</li>
<li>
<p>foo</p>
</li>
</ul>
<!-- -->
<pre><code>code
</code></pre>
列表项不需要缩进到同一级别。下列 列表项将被视为同一列表级别的项目, 因为没有一个缩进足以属于前一个列表 物品:
- a
- b
- c
- d
- e
- f
- g
<ul>
<li>a</li>
<li>b</li>
<li>c</li>
<li>d</li>
<li>e</li>
<li>f</li>
<li>g</li>
</ul>
但请注意,列表项前面的字符不得超过
三个空格的缩进。这里 - e
被视为段落延续
行,因为它缩进超过三个空格:
而在这里, 3. c
被视为缩进代码块,
因为它缩进了四个空格并且前面有一个
空行。
1. a
2. b
3. c
<ol>
<li>
<p>a</p>
</li>
<li>
<p>b</p>
</li>
</ol>
<pre><code>3. c
</code></pre>
这是一个松散列表,因为之间有一个空行 其中两个列表项:
这也是,第二项为空:
这些是松散的列表,即使项目之间没有空行, 因为其中一项直接包含两个块级元素 它们之间有一个空行:
- a
- b
c
- d
<ul>
<li>
<p>a</p>
</li>
<li>
<p>b</p>
<p>c</p>
</li>
<li>
<p>d</p>
</li>
</ul>
- a
- b
[ref]: /url
- d
<ul>
<li>
<p>a</p>
</li>
<li>
<p>b</p>
</li>
<li>
<p>d</p>
</li>
</ul>
这是一个很紧凑的列表,因为空行位于代码块中:
- a
- ```
b
```
- c
<ul>
<li>a</li>
<li>
<pre><code>b
</code></pre>
</li>
<li>c</li>
</ul>
这是一个很紧凑的列表,因为空行位于两个之间 子列表的段落。所以子列表是松散的 外部列表很紧:
这是一个很紧凑的列表,因为空行位于 块引用:
这个列表很紧,因为连续的块元素 不以空行分隔:
- a
> b
```
c
```
- d
<ul>
<li>a
<blockquote>
<p>b</p>
</blockquote>
<pre><code>c
</code></pre>
</li>
<li>d</li>
</ul>
单段落列表很紧凑:
这个列表很松散,因为之间有空行 列表项中的两个块元素:
这里外部列表是松散的,内部列表是紧密的:
- a
- b
- c
- d
- e
- f
<ul>
<li>
<p>a</p>
<ul>
<li>b</li>
<li>c</li>
</ul>
</li>
<li>
<p>d</p>
<ul>
<li>e</li>
<li>f</li>
</ul>
</li>
</ul>
内联从字符的开头按顺序解析 流到末尾(从左到右,在从左到右的语言中)。 因此,例如,在
hi
被解析为代码,将末尾的反引号保留为文字
反引号。
字符串 反引号
是一串由一个或多个反引号字符组成的字符串 ( `
)这两者都不是
前面或后面都有反引号。
以 代码范围 反引号字符串开头并以 长度相等的反引号字符串。代码范围的内容是 这两个反引号字符串之间的字符,在 以下方式:
这是一个简单的代码范围:
这里使用了两个反引号,因为代码中包含一个反引号。 此示例还说明了单个前导和的剥离 尾随空格:
此示例显示了剥离前导和尾随的动机 空格:
请注意,仅 一个空格: 删除
仅当两者上都有空格时才会发生剥离 字符串的两侧:
只有 空格 ,而不是 unicode 空白 一般的 以这种方式剥离:
如果代码范围仅包含空格,则不会发生剥离:
行结尾 被视为空格:
内部空间未塌陷:
请注意,浏览器通常会折叠连续的空格
渲染时 <code>
元素,所以建议
使用以下 CSS:
code{white-space: pre-wrap;}
请注意,反斜杠转义在代码跨度中不起作用。所有反斜杠 按字面意思处理:
永远不需要反斜杠转义,因为人们总是可以选择一个 反引号字符作为分隔符的字符串 由n 个 ,其中代码的作用 反引号字符的字符串 不包含任何正好有n 个 。
代码跨度反引号的优先级高于任何其他内联
除 HTML 标签和自动链接之外的构造。因此,例如,这是
没有被解析为强调文本,因为第二个 *
是代码的一部分
跨度:
这不会被解析为链接:
代码范围、HTML 标签和自动链接具有相同的优先级。 因此,这是代码:
但这是一个 HTML 标签:
这是代码:
但这是一个自动链接:
<https://foo.bar.`baz>`
<p><a href="https://foo.bar.%60baz">https://foo.bar.`baz</a>`</p>
当反引号字符串没有被匹配的反引号字符串封闭时, 我们只有字面上的反引号:
下面的案例也说明了开放和开放的必要性 关闭反引号字符串的长度相等:
John Gruber 最初的 Markdown 语法 描述 说:
Markdown 处理星号(
*
) 和下划线 (_
)作为指标 强调。用 1 包裹的文本*
或者_
将被 HTML 包裹<em>
标签;双倍的*
的或_
的将被 HTML 包裹<strong>
标签。
这对于大多数用户来说已经足够了,但是这些规则还有很多不确定之处,
尤其是当涉及到嵌套强调时。原来的
Markdown.pl
测试套件清楚地表明三重 ***
和
___
分隔符可用于强调强调,并且大多数
实现还允许以下模式:
***strong emph***
***strong** in emph*
***emph* in strong**
**in strong *emph***
*in emph **strong***
以下模式不太受广泛支持,但其意图 很清楚并且很有用(特别是在参考书目等上下文中 条目):
*emph *with emph* in it*
**strong **with strong** in it**
许多实现也将字内强调限制为
这 *
形式,以避免不必要的强调包含
内部下划线。 (最好的做法是将这些放入代码中
跨度,但用户通常不这样做。)
internal emphasis: foo*bar*baz
no emphasis: foo_bar_baz
下面给出的规则捕获了所有这些模式,同时允许 用于不回溯的高效解析策略。
首先,一些定义。 运行 分隔符 是
一个或多个的序列 *
前面没有的字符或
后跟一个非反斜杠转义的 *
字符或序列
一个或多个的 _
前面或后面没有的字符
非反斜杠转义 _
特点。
左侧 分隔符运行 是 分隔符 运行 (1) 后面不跟 Unicode 空格的 , 并且 (2a) 后面不跟有 Unicode 标点符号 ,或者 (2b) 后跟 Unicode 标点符号 和 前面有 Unicode 空格 或 Unicode 标点符号 。 就本定义而言,开头和结尾 行计数为 Unicode 空白。
运行 右侧分隔符 是 的分隔符 运行 (1) 前面没有 Unicode 空格 , 并且 (2a) 前面没有 Unicode 标点符号 ,或者 (2b) 前面有一个 Unicode 标点符号 ,并且 后跟 Unicode 空格 或 Unicode 标点符号 。 就本定义而言,开头和结尾 行计数为 Unicode 空白。
以下是分隔符运行的一些示例。
左侧但不是右侧:
***abc
_abc
**"abc"
_"abc"
位于右侧但不位于左侧:
abc***
abc_
"abc"**
"abc"_
左右两侧:
abc***def
"abc"_"def"
既不是左翼也不是右翼:
abc *** def
a _ b
(区分左翼和右翼的想法 分隔符根据前面的字符和后面的字符运行 之后来自 Roopesh Chander 的 vfmd 。 vfmd 使用术语“强调指示符字符串”而不是“分隔符” 跑动”以及区分左翼和右翼跑动的规则 比这里给出的要复杂一些。)
以下规则定义了强调和强烈强调:
单个 _
角色 可以打开强调 iff
的一部分 它是左侧分隔符运行
并且 (a) 不是 右侧分隔符运行 的一部分
的一部分 或 (b)右侧分隔符运行
前面是 Unicode 标点符号 。
单个 _
字符 可以关闭强调 iff
的一部分 它是右侧分隔符运行
并且 (a) 不是 左侧分隔符运行 的一部分
的一部分 或 (b)左侧分隔符运行
后跟一个 Unicode 标点符号 。
一个双人 __
可以打开强强调 iff
的一部分 它是左侧分隔符运行
并且 (a) 不是 右侧分隔符运行 的一部分
的一部分 或 (b)右侧分隔符运行
前面是 Unicode 标点符号 。
一个双人 __
可以关闭强强调 iff
的一部分 它是右侧分隔符运行
并且 (a) 不是 左侧分隔符运行 的一部分
的一部分 或 (b)左侧分隔符运行
后跟一个 Unicode 标点符号 。
分隔符开始 强调以可以打开强调 并结束的
的分隔符 带有可以关闭强调 ,并且使用相同的
特点 ( _
或者 *
) 作为开始分隔符。这
开始和结束分隔符必须属于单独的
分隔符运行 。如果分隔符之一可以同时
开重点和闭重点,然后是长度的总和
包含开始和结束定界符的定界符运行
不能是 3 的倍数,除非两个长度都是
3的倍数。
强调强调以分隔符开始
可以打开强调 并以分隔符结尾
可以关闭强强调 ,并且使用相同的字符
( _
或者 *
) 作为开始分隔符。这
开始和结束分隔符必须属于单独的
分隔符运行 。如果分隔符之一可以同时打开
并密切强调,然后长度的总和
分隔符包含开始和结束
分隔符不能是 3 的倍数,除非两个长度
是3的倍数。
字面意义 *
字符不能出现在开头或结尾
*
- 分隔强调或 **
- 分隔强调重点,除非它
是反斜杠转义的。
字面意义 _
字符不能出现在开头或结尾
_
- 分隔强调或 __
- 分隔强调重点,除非它
是反斜杠转义的。
其中上述规则 1-12 与多重解析兼容, 以下原则可以解决歧义:
应尽量减少嵌套数量。因此,例如,
一种解释 <strong>...</strong>
总是优先于
<em><em>...</em></em>
。
一个解读 <em><strong>...</strong></em>
总是
更喜欢 <strong><em>...</em></strong>
。
当两个潜在的重点或强重点跨度重叠时,
这样第二个在第一个结束之前开始并在第一个结束之后结束
第一个结束,第一个优先。因此,例如,
*foo _bar* baz_
被解析为 <em>foo _bar</em> baz_
相当
比 *foo <em>bar* baz</em>
。
当有两个潜在的重点或强重点跨度时
具有相同的结束分隔符,较短的那个(那个
稍后打开)优先。因此,例如,
**foo **bar baz**
被解析为 **foo <strong>bar baz</strong>
而不是 <strong>foo **bar baz</strong>
。
内联代码跨度、链接、图像和 HTML 标签组合得更紧密
比强调。因此,当在解释之间做出选择时
包含这些元素之一和不包含其中一个元素的
前者总是获胜。因此,例如, *[foo*](bar)
是
解析为 *<a href="bar">foo*</a>
而不是作为
<em>[foo</em>](bar)
。
这些规则可以通过一系列例子来说明。
规则 1:
这不是强调,因为开头 *
接下来是
空格,因此不是 左侧分隔符运行 的一部分:
这不是强调,因为开头 *
位于之前
由字母数字组成,后跟标点符号,因此
的一部分 不是左侧分隔符运行 :
Unicode 不间断空格也算作空白:
Unicode 符号也算作标点符号:
词内强调 *
是允许的:
规则 2:
这不是强调,因为开头 _
接下来是
空白:
这不是强调,因为开头 _
位于之前
由字母数字和标点符号组成:
强调与 _
不允许在以下单词中使用:
这里 _
不会产生强调,因为第一个分隔符运行
是右翼,第二个是左翼:
这是强调,即使开始分隔符是 左侧和右侧,因为它前面是 标点:
规则 3:
这不是强调,因为结束定界符 与开始分隔符不匹配:
这不是强调,因为结束语 *
前面是
空白:
行结尾也算作空格:
这不是强调,因为第二个 *
是
前面是标点符号,后面是字母数字
(因此它不是 右侧分隔符运行 的一部分:
这种限制的意义更容易理解 以此为例:
词内强调 *
允许:
规则 4:
这不是强调,因为结束语 _
前面是
空白:
这不是强调,因为第二个 _
是
前面是标点符号,后面是字母数字:
这是强调中的强调:
不允许使用词内强调 _
:
这是强调,即使结束分隔符是 左侧和右侧,因为它后面是 标点:
规则 5:
这不是重点强调,因为开始分隔符是 后面跟着空格:
这不是重点强调,因为开头 **
位于之前
由字母数字组成,后跟标点符号,因此
的一部分 不是左侧分隔符运行 :
词内强调 **
是允许的:
规则 6:
这不是重点强调,因为开始分隔符是 后面跟着空格:
行结尾算作空格:
这不是重点强调,因为开头 __
位于之前
由字母数字和标点符号组成:
禁止词内强调 __
:
这是强烈强调,即使开始分隔符是 左侧和右侧,因为它前面是 标点:
规则 7:
这不是重点强调,因为结束分隔符位于前面 通过空格:
(也不能理解为强调 *foo bar *
,因为
规则 11。)
这不是重点强调,因为第二个 **
是
前面是标点符号,后面是字母数字:
这种限制的意义更容易理解 通过这些例子:
**Gomphocarpus (*Gomphocarpus physocarpus*, syn.
*Asclepias physocarpa*)**
<p><strong>Gomphocarpus (<em>Gomphocarpus physocarpus</em>, syn.
<em>Asclepias physocarpa</em>)</strong></p>
词内强调:
规则 8:
这不是重点强调,因为结束分隔符是 前面有空格:
这不是重点强调,因为第二个 __
是
前面是标点符号,后面是字母数字:
这种限制的意义更容易理解 以此为例:
禁止词内强调 __
:
这是强烈强调,即使结束分隔符是 左侧和右侧,因为它后面是 标点:
规则 9:
任何非空的内联元素序列都可以是 强调跨度。
特别是,强调和强调可以嵌套 里面强调:
请注意,在前面的情况下,解释
<p><em>foo</em><em>bar<em></em>baz</em></p>
被排除的条件是分隔符
可以打开和关闭(就像 *
后 foo
)
如果长度之和不能形成强调
分隔符包含开头和
结束分隔符是 3 的倍数,除非
两个长度都是 3 的倍数。
出于同样的原因,我们不会连续获得两个 本例中的重点部分:
相同的条件确保以下 案例都强调嵌套在里面 强调,即使内部空白是 省略:
当内部关闭和打开的长度 不过,分隔符都是 3 的倍数, 它们可以匹配以强调:
foo******bar*********baz
<p>foo<strong><strong><strong>bar</strong></strong></strong>***baz</p>
无限级嵌套是可能的:
*foo **bar *baz* bim** bop*
<p><em>foo <strong>bar <em>baz</em> bim</strong> bop</em></p>
不能有空强调或强强调:
规则 10:
任何非空的内联元素序列都可以是 强烈强调跨度。
特别是,强调和强调可以嵌套 里面强调:
无限级嵌套是可能的:
**foo *bar **baz**
bim* bop**
<p><strong>foo <em>bar <strong>baz</strong>
bim</em> bop</strong></p>
不能有空强调或强强调:
规则 11:
请注意,当分隔符不均匀匹配时,规则 11 确定
多余的文字 *
字符将出现在
强调,而不是在里面:
规则 12:
请注意,当分隔符不均匀匹配时,规则 12 确定
多余的文字 _
字符将出现在
强调,而不是在里面:
规则 13 意味着如果你想强调直接嵌套在 强调,您必须使用不同的分隔符:
然而,在不强调的情况下,强调中的强调也是可能的。 切换分隔符:
规则 13 可以应用于任意长的序列 分隔符:
规则 14:
规则 15:
规则 16:
规则 17:
**a<https://foo.bar/?q=**>
<p>**a<a href="https://foo.bar/?q=**">https://foo.bar/?q=**</a></p>
__a<https://foo.bar/?q=__>
<p>__a<a href="https://foo.bar/?q=__">https://foo.bar/?q=__</a></p>
链接包含 链接文本 (可见文本)、 链接目标 (作为链接目标的 URI),以及可选的 链接标题 。 Markdown 中有两种基本类型的链接。 中 在内联 链接 链接文本后立即给出目的地和标题。在 参考链接的 目的地和标题在其他地方定义 该文件。
由 链接文本 零个或多个序列组成
用方括号括起来的内联元素 ( [
和 ]
)。这
适用以下规则:
链接不得包含任何嵌套级别的其他链接。如果 多个原本有效的链接定义嵌套在每个链接定义中 其他的,使用最里面的定义。
才允许在 链接文本 仅当满足以下条件时, 中使用方括号:
是反斜杠转义的或者 (b) 它们显示为一对匹配的括号,
带开括号 [
、零个或多个内联序列,以及
右括号 ]
。
反引号 代码跨度 、 自动链接 和原始 HTML 标记 结合得更紧密
比链接文本中的括号更重要。因此,例如,
[foo`]`
不能是链接文本,因为第二个 ]
是代码跨度的一部分。
链接文本中的括号比标记绑定得更紧密
强调和强烈强调 。因此,例如, *[foo*](url)
是一个链接。
由 链接目标 以下任一组成:
开头之间的零个或多个字符的序列 <
和一个
关闭 >
不包含行结尾或未转义的
<
或者 >
字符,或
不以以下字符开头的非空字符序列 <
,
不包括 ASCII 控制字符
或 空格 字符,并且仅在以下情况下才包含括号:(a)
反斜杠转义或 (b) 它们是一对平衡的一部分
未转义的括号。
(实现可能会对括号嵌套施加限制
避免性能问题,但至少三层嵌套
应该支持。)
由 链接标题 以下任一组成
直双引号之间的零个或多个字符的序列
人物 ( "
),包括一个 "
仅当它是字符时
反斜杠转义,或者
直单引号之间的零个或多个字符的序列
人物 ( '
),包括一个 '
仅当它是字符时
反斜杠转义,或者
匹配括号之间的零个或多个字符的序列
( (...)
),包括一个 (
或者 )
仅当它是字符时
反斜杠转义。
尽管 链接标题 可能跨越多行,但它们可能不包含 一个 空行 。
由 内联链接 组成 链接文本 紧随其后的
通过左括号 (
,一个可选的 链接目标 ,一个可选的
链接标题 和右括号 )
。
这四个部分可以用空格、制表符和最多一行分隔
结束。
如果 链接目标 和 链接标题 都存在,则它们 必须 是
以空格、制表符和最多一行结尾分隔。
链接的文本由包含的内联内容组成
在 链接文本 中(不包括方括号)。
链接的 URI 由链接目标组成,不包括封闭的
<...>
如果存在,则反斜杠转义有效,如所述
多于。链接的标题由链接标题组成,不包括其内容
封闭分隔符,反斜杠转义有效,如所述
多于。
这是一个简单的内联链接:
标题、链接文本甚至 目的地可以省略:
目的地只能包含空格 用尖括号括起来:
目标不能包含行结尾, 即使用尖括号括起来:
目的地可以包含 )
如果是封闭的
在尖括号中:
包含链接的尖括号必须不转义:
这些不是链接,因为左尖括号 没有正确匹配:
链接目标内的括号可能会被转义:
允许使用任意数量的括号而不转义,只要它们是 均衡:
但是,如果括号不平衡,则需要转义或使用
<...>
形式:
像往常一样,括号和其他符号也可以转义 在降价中:
链接可以包含片段标识符和查询:
[link](#fragment)
[link](https://example.com#fragment)
[link](https://example.com?foo=3#frag)
<p><a href="#fragment">link</a></p>
<p><a href="https://example.com#fragment">link</a></p>
<p><a href="https://example.com?foo=3#frag">link</a></p>
请注意,不可转义字符之前的反斜杠是 只是一个反斜杠:
URL 转义应该单独留在目标中,因为所有 URL 转义字符也是有效的 URL 字符。实体和 将解析目标中的数字字符引用 像往常一样转换成相应的 Unicode 代码点。这些可能 当以 HTML 形式编写时,可以选择进行 URL 转义,但是此规范 不强制执行任何特定的 URL 渲染策略 HTML 或其他格式。渲染器可能会做出不同的决定 关于如何转义或标准化输出中的 URL。
请注意,因为标题通常可以被解析为目的地, 如果您尝试省略目的地并保留标题,您将 得到意想不到的结果:
标题可以用单引号、双引号或括号括起来:
[link](/url "title")
[link](/url 'title')
[link](/url (title))
<p><a href="/url" title="title">link</a>
<a href="/url" title="title">link</a>
<a href="/url" title="title">link</a></p>
反斜杠转义以及实体和数字字符引用 可用于标题:
标题与链接之间必须使用空格、制表符和最多一行分隔开 结束。 其他 Unicode 空白 (例如不间断空格)不起作用。
不允许嵌套平衡引号而不转义:
[link](/url "title "and" title")
<p>[link](/url "title "and" title")</p>
但通过使用不同的引用类型很容易解决这个问题:
[link](/url 'title "and" title')
<p><a href="/url" title="title "and" title">link</a></p>
(笔记: Markdown.pl
确实允许在双引号内使用双引号
标题,其测试套件包括一个证明这一点的测试。
但很难找到一个合理的理由来解释这种额外的复杂性。
带来,因为已经有很多方法——反斜杠转义,
实体和数字字符引用,或使用不同的
封闭标题的引用类型——编写包含以下内容的标题
双引号。 Markdown.pl
对标题的处理有很多
其他奇怪的功能。例如,它允许单引号
内联链接中的标题,但参考链接中不包括。并且,在
参考链接但不是内联链接,它允许标题开始
和 "
并结束于 )
。 Markdown.pl
1.0.1甚至允许
标题没有右引号,但 1.0.2b8 没有。
似乎最好采用一种简单、合理且行之有效的规则
在内联链接和链接引用定义中也是如此。)
目标周围允许有空格、制表符和最多一行结尾 标题:
但链接文本和链接文本之间不允许存在 下面的括号:
链接文本可以包含平衡括号,但不能包含不平衡括号, 除非他们逃脱了:
链接文本可能包含内联内容:
[link *foo **bar** `#`*](/uri)
<p><a href="/uri">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>
但是,链接在任何嵌套级别都不得包含其他链接。
[foo *[bar [baz](/uri)](/uri)*](/uri)
<p>[foo <em>[bar <a href="/uri">baz</a>](/uri)</em>](/uri)</p>
这些案例说明了链接文本分组的优先级 重点分组:
属于链接一部分的括号 请注意,不 不会占用 优先级:
这些案例说明了 HTML 标签、代码跨度的优先级, 以及通过链接分组自动链接:
[foo<https://example.com/?search=](uri)>
<p>[foo<a href="https://example.com/?search=%5D(uri)">https://example.com/?search=](uri)</a></p>
分为三种 参考链接 : 饱满 、 塌陷 、 和 快捷方式 。
链接 完整的参考 组成 的链接文本 由紧跟 链接标签 与 相匹配。 链接 引用定义 文档中其他地方的
以 链接标签 左括号 ( [
) 并结束
与第一个右括号 ( ]
) 不是反斜杠转义的。
这些括号之间必须至少有一个不是空格的字符,
制表符或行结尾。
内部不允许使用未转义的方括号字符
的左方括号和右方括号 链接标签 。一个链接
标签在方块内最多可以有 999 个字符
括号。
一个标签 匹配 另一个以防万一它们的标准化形式相等。标准化一个 标签,剥去左括号和右括号, 执行 Unicode 大小写折叠 、剥离前导和尾随 空格、制表符和行结尾,以及折叠连续的内部 将空格、制表符和行结尾合并为一个空格。如果有多个 匹配参考链接定义,即第一个链接定义 使用文档。 (在这种情况下最好发出警告。)
链接的 URI 和标题由匹配的 链接 提供 参考定义 。
这是一个简单的例子:
链接文本可以包含平衡括号,但不能包含不平衡括号, 除非他们逃脱了:
链接文本可能包含内联内容:
[link *foo **bar** `#`*][ref]
[ref]: /uri
<p><a href="/uri">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>
[![moon](moon.jpg)][ref]
[ref]: /uri
<p><a href="/uri"><img src="moon.jpg" alt="moon" /></a></p>
但是,链接在任何嵌套级别都不得包含其他链接。
[foo [bar](/uri)][ref]
[ref]: /uri
<p>[foo <a href="/uri">bar</a>]<a href="/uri">ref</a></p>
[foo *bar [baz][ref]*][ref]
[ref]: /uri
<p>[foo <em>bar <a href="/uri">baz</a></em>]<a href="/uri">ref</a></p>
(在上面的示例中,我们有两个 快捷参考链接 而不是一个 完整的参考链接 。)
以下情况说明了链接文本分组的优先级 重点分组:
这些案例说明了 HTML 标签、代码跨度的优先级, 以及通过链接分组自动链接:
[foo<https://example.com/?search=][ref]>
[ref]: /uri
<p>[foo<a href="https://example.com/?search=%5D%5Bref%5D">https://example.com/?search=][ref]</a></p>
匹配不区分大小写:
使用 Unicode 大小写折叠:
连续的内部空格、制表符和行结尾被视为一个空格 确定匹配的目的:
之间不允许有空格、制表符或行结尾 链接文本 和链接文本 链接标签 :
这与 John Gruber 最初的 Markdown 语法不同 描述,明确允许链接之间有空格 文本和链接标签。它带来的参考链接符合 内联链接 ,(根据原始 Markdown 和 本规范)链接文本后不能有空格。更多的 重要的是,它可以防止无意中捕获连续的 快捷参考链接 。如果之间允许有空格 链接文本和链接标签,那么在下面我们将有 单个参考链接,而不是两个快捷参考链接,如 故意的:
[foo]
[bar]
[foo]: /url1
[bar]: /url2
(请注意, 快捷方式参考链接 是由 Gruber 引入的
他自己在测试版中 Markdown.pl
,但从未包括在内
在官方语法描述中。无快捷方式参考
链接,在链接文本和链接文本之间留有空格是无害的
链接标签;但是一旦引入了快捷方式引用,
允许这样做太危险了,因为它经常导致
意想不到的结果。)
当存在多个匹配的 链接引用定义 时, 第一个使用:
请注意,匹配是在规范化字符串上执行的,而不是解析的 内联内容。因此以下内容不匹配,即使 标签定义等效的内联内容:
链接标签 不能包含括号,除非它们是 反斜杠转义:
请注意,在此示例中 ]
不是反斜杠转义的:
必须 链接标签 至少包含一个不是空格、制表符或制表符的字符 行尾:
链接 折叠的参考
组成 链接 的 由匹配 标签
链接参考定义 在其他地方
文档,后跟字符串 []
。
链接标签的内容被解析为内联,
用作链接的文本。链接的 URI 和标题是
由匹配的参考链接定义提供。因此,
[foo][]
相当于 [foo][foo]
。
[*foo* bar][]
[*foo* bar]: /url "title"
<p><a href="/url" title="title"><em>foo</em> bar</a></p>
链接标签不区分大小写:
与完整的参考链接一样,空格、制表符或行结尾不是 两组括号之间允许:
链接 快捷参考
组成 链接 的 由匹配 标签
链接参考定义 在其他地方
文件并且后面没有 []
或链接标签。
链接标签的内容被解析为内联,
用作链接的文本。链接的 URI 和标题
由匹配的链接参考定义提供。
因此, [foo]
相当于 [foo][]
。
[*foo* bar]
[*foo* bar]: /url "title"
<p><a href="/url" title="title"><em>foo</em> bar</a></p>
[[*foo* bar]]
[*foo* bar]: /url "title"
<p>[<a href="/url" title="title"><em>foo</em> bar</a>]</p>
链接标签不区分大小写:
应保留链接文本后的空格:
如果您只想要括号内的文本,则可以反斜杠转义 打开括号以避免链接:
请注意,这是一个链接,因为链接标签以第一个结尾 以下右括号:
完整和折叠引用优先于快捷方式 参考:
内联链接也优先:
在以下情况下 [bar][baz]
被解析为参考,
[foo]
作为普通文本:
不过在这里, [foo][bar]
被解析为参考,因为
[bar]
定义为:
[foo][bar][baz]
[baz]: /url1
[bar]: /url2
<p><a href="/url2">foo</a><a href="/url1">baz</a></p>
这里 [foo]
不会被解析为快捷方式引用,因为它
后面跟着一个链接标签(尽管 [bar]
未定义):
图像的语法类似于链接的语法,其中一个
不同之处。 而是 我们没有链接文本 ,
图像描述 。这样做的规则是
相同 与链接文本 ,除了 (a)
图像描述开头为 ![
而不是 [
, 和
(b) 图像描述可以包含链接。
图像描述具有内联元素
作为其内容。当图像呈现为 HTML 时,
这通常用作图像的 alt
属性。
![foo *bar*]
[foo *bar*]: train.jpg "train & tracks"
<p><img src="train.jpg" alt="foo bar" title="train & tracks" /></p>
尽管此规范涉及解析,而不是渲染,但它是
建议在渲染为 HTML 时,仅使用纯字符串内容
的一部分 图像描述 使用 。请注意,在
上面的例子中,alt属性的值为 foo bar
, 不是 foo [bar](/url)
或者 foo <a href="/url">bar</a>
。仅纯字符串
内容被渲染,没有格式化。
![foo *bar*][]
[foo *bar*]: train.jpg "train & tracks"
<p><img src="train.jpg" alt="foo bar" title="train & tracks" /></p>
![foo *bar*][foobar]
[FOOBAR]: train.jpg "train & tracks"
<p><img src="train.jpg" alt="foo bar" title="train & tracks" /></p>
My ![foo bar](/path/to/train.jpg "title" )
<p>My <img src="/path/to/train.jpg" alt="foo bar" title="title" /></p>
参考风格:
折叠:
![*foo* bar][]
[*foo* bar]: /url "title"
<p><img src="/url" alt="foo bar" title="title" /></p>
标签不区分大小写:
与参考链接一样,不允许使用空格、制表符和行结尾 两组括号之间:
捷径:
![*foo* bar]
[*foo* bar]: /url "title"
<p><img src="/url" alt="foo bar" title="title" /></p>
请注意,链接标签不能包含未转义的括号:
链接标签不区分大小写:
如果你只想要一个字面意思 !
后面是括号内的文本,您可以
反斜杠-转义开头 [
:
如果您想在文字后面添加链接 !
, 反斜杠转义
!
:
Autolink 是里面的绝对 URI 和电子邮件地址
<
和 >
。它们被解析为带有 URL 或电子邮件地址的链接
作为链接标签。
URI 自动链接 包括 <
,后面跟着一个
绝对 URI 后跟 >
。它被解析为
指向 URI 的链接,以 URI 作为链接的标签。
URI 绝对 ,
出于这些目的,由一个 方案 组成,后跟一个冒号( :
)
后跟零个或多个除 ASCII 控制 之外的字符
字符 、 空间 、 <
, 和 >
。
如果 URI 包含这些字符,则它们必须进行百分比编码
(例如 %20
为一个空间)。
就本规范而言, 方案 是任何序列 由 2–32 个字符组成,以 ASCII 字母开头,后跟 由 ASCII 字母、数字或符号加号的任意组合 (“+”)、句点(“.”)或连字符(“-”)。
以下是一些有效的自动链接:
<https://foo.bar.baz/test?q=hello&id=22&boolean>
<p><a href="https://foo.bar.baz/test?q=hello&id=22&boolean">https://foo.bar.baz/test?q=hello&id=22&boolean</a></p>
<irc://foo.bar:2233/baz>
<p><a href="irc://foo.bar:2233/baz">irc://foo.bar:2233/baz</a></p>
大写也可以:
请注意,许多字符串被视为 URI 绝对 本规范的目的不是有效的 URI,因为它们 计划未注册或由于其他问题 及其语法:
<made-up-scheme://foo,bar>
<p><a href="made-up-scheme://foo,bar">made-up-scheme://foo,bar</a></p>
自动链接中不允许有空格:
反斜杠转义在自动链接内不起作用:
<https://example.com/\[\>
<p><a href="https://example.com/%5C%5B%5C">https://example.com/\[\</a></p>
电子邮件 自动链接
包括 <
,后跟 电子邮件地址 ,
其次是 >
。链接的标签是电子邮件地址,
网址是 mailto:
接下来是电子邮件地址。
一个 电子邮件地址 , 出于这些目的,任何匹配的东西 表达式 HTML5 中的非规范正则 规格 :
/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?
(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/
电子邮件自动链接的示例:
<foo@bar.example.com>
<p><a href="mailto:foo@bar.example.com">foo@bar.example.com</a></p>
<foo+special@Bar.baz-bar0.com>
<p><a href="mailto:foo+special@Bar.baz-bar0.com">foo+special@Bar.baz-bar0.com</a></p>
反斜杠转义符在电子邮件自动链接内不起作用:
这些不是自动链接:
之间的文本 <
和 >
看起来 HTML 标签被解析为
原始 HTML 标签并将在不转义的情况下以 HTML 形式呈现。
标签和属性名称不限于当前的 HTML 标签,
因此可以使用自定义标签(甚至 DocBook 标签)。
这是标签的语法:
由 标签名称 ASCII 字母组成
后跟零个或多个 ASCII 字母、数字或
连字符( -
)。
属性 由空格 、制表符和最多一个行结尾组成, 和 属性名称 可选的 属性值规范 。
名称 属性
由一个 ASCII 字母组成, _
, 或者 :
,后跟零个或多个 ASCII
字母、数字、 _
, .
, :
, 或者 -
。 (注:这是 XML
规范仅限于 ASCII。 HTML5 更宽松。)
属性 值规范
由可选空格、制表符和最多一行结尾组成,
一个 =
字符、可选空格、制表符和最多一行结尾,
和一个 属性值 。
值 属性 组成 由不带引号的属性值 , 单 引号属性值 或 双引号属性值 。
值 不带引号的属性
是一个非空字符串,不是
包括空格、制表符、行结束符、 "
, '
, =
, <
, >
, 或者 `
。
值 单引号属性
包括 '
, 零个或多个
字符不包括 '
,以及最终的 '
。
值 双引号属性
包括 "
, 零个或多个
字符不包括 "
,以及最终的 "
。
标签 开放 由 <
字符, 标签名称 ,
零个或多个 属性 、可选空格、制表符和最多一行结尾,
一个可选的 /
角色,以及一个 >
特点。
由 结束标签 字符串组成 </
, 一个
标签名称 、可选空格、制表符、最多一行结尾以及字符
>
。
由 HTML 注释 以下部分组成 <!-->
, <!--->
, 或者 <!--
,一串
不包括字符串的字符 -->
, 和 -->
(参见
HTML 规范 )。
一条 处理指令
由字符串组成 <?
, 一个字符串
不包括字符串的字符数 ?>
,和字符串
?>
。
声明 由字符串 组成 <!
, 一个 ASCII 字母,零个或多个
不包含该字符的字符 >
,以及角色 >
。
部分 CDATA 包括
字符串 <![CDATA[
, 不包含字符串的字符串
]]>
,和字符串 ]]>
。
由 HTML 标签 开始 标签 、 结束标签 、 、 HTML 注释 处理 指令 、 声明 、 或 CDATA 部分 。
以下是一些简单的开放标签:
空元素:
允许使用空格:
具有属性:
<a foo="bar" bam = 'baz <em>"</em>'
_boolean zoop:33=zoop:33 />
<p><a foo="bar" bam = 'baz <em>"</em>'
_boolean zoop:33=zoop:33 /></p>
可以使用自定义标签名称:
非法标签名称,未解析为 HTML:
非法属性名称:
非法属性值:
非法空格:
< a><
foo><bar/ >
<foo bar=baz
bim!bop />
<p>< a><
foo><bar/ >
<foo bar=baz
bim!bop /></p>
缺少空格:
结束标签:
结束标记中的非法属性:
评论:
foo <!-- this is a --
comment - with hyphens -->
<p>foo <!-- this is a --
comment - with hyphens --></p>
foo <!--> foo -->
foo <!---> foo -->
<p>foo <!--> foo --></p>
<p>foo <!---> foo --></p>
加工说明:
声明:
CDATA 部分:
实体和数字字符引用保留在 HTML 中 属性:
反斜杠转义在 HTML 属性中不起作用:
前面的行结尾(不在代码范围或 HTML 标记中)
由两个或多个空格组成,并且不会出现在块的末尾
被解析为 硬换行符 (呈现
在 HTML 中作为 <br />
标签):
对于更明显的替代方案,在前面加一个反斜杠 可以使用行结尾 代替两个或多个空格:
可以使用两个以上的空格:
下一行开头的前导空格将被忽略:
硬换行可能发生在强调、链接和其他结构中 允许内联内容:
代码范围内不会发生硬换行
或 HTML 标签:
硬换行符用于分隔块内的内联内容。 硬换行符的语法在段落末尾或 其他块元素:
不存在的常规行结尾(不在代码范围或 HTML 标记中) 前面有两个或多个空格或反斜杠被解析为 软中断 。 (软换行符可以在 HTML 中呈现为 行尾 或作为空格。结果将是相同的 浏览器。在此示例中, 行结尾。) 将使用
行尾和下一行开头的空格是 删除:
符合标准的解析器可以将 HTML 中的软换行符呈现为 行尾或作为空格。
渲染器还可以提供渲染软换行符的选项 当硬线断裂时。
任何未按上述规则解释的字符将 被解析为纯文本内容。
内部空间被逐字保留:
在本附录中,我们描述了解析策略的一些特征 在 CommonMark 参考实现中使用。
解析有两个阶段:
在第一阶段,消耗输入行并且块 文档的结构——段落的划分、引用块、 列表项等等——被构造。文本被分配给这些 块但未解析。解析链接引用定义并生成 链接图已构建。
第二阶段,段落和标题的原始文本内容 被解析为 Markdown 内联元素序列(字符串、 代码跨度、链接、强调等),使用链接图 第一阶段构建的参考文献。
在处理的每个点,文档都被表示为一棵树
块 。树的根是一个 document
堵塞。这 document
可以有任意数量的其他块作为 子块 。这些孩子
反过来,可能还有其他子块。块的最后一个孩子
通常被认为是 open ,这意味着后续的输入行
可以改变其内容。 (未打开的块将被 关闭 。)
例如,这里是一个可能的文档树,其中包含开放块
用箭头标记:
-> document
-> block_quote
paragraph
"Lorem ipsum dolor\nsit amet."
-> list (type=bullet tight=true bullet_char=-)
list_item
paragraph
"Qui *quodsi iracundia*"
-> list_item
-> paragraph
"aliquando id"
处理的每一行都会对该树产生影响。该行是 进行分析,并且根据其内容,该文件可能会被更改 通过以下一种或多种方式:
一旦以这种方式将一条线合并到树中, 它可以被丢弃,因此可以在流中读取输入。
对于每一行,我们都遵循以下过程:
首先,我们迭代开放的块,从
根文档,并从最后一个子文档下降到最后一个
开块。每个块都强加了该行必须满足的条件
如果该块要保持打开状态。例如,块引用需要
>
特点。段落要求非空行。
在此阶段,我们可能会匹配所有或仅部分开放的
块。但我们还不能关闭不匹配的块,因为我们可能有一个
懒惰的续行 。
接下来,在消耗现有的延续标记之后
块,我们寻找新的块开始(例如 >
以获得块报价)。
如果我们遇到新的块开始,我们会关闭所有不匹配的块
在步骤 1 中,在创建新块作为最后一个块的子块之前
匹配的容器块。
最后,我们看看该行的其余部分(在块之后
标记如 >
、列表标记和缩进已被消耗)。
这是可以合并到最后打开的文本中
块(段落、代码块、标题或原始 HTML)。
当我们看到段落的一行时,就形成了 Settext 标题 这是一个 setext 标题下划线 。
当段落关闭时检测参考链接定义; 解析累积的文本行以查看它们是否以 一个或多个参考链接定义。任何余数都变成 正常段落。
我们可以通过考虑上面的树来了解它是如何工作的 由四行 Markdown 生成:
> Lorem ipsum dolor
sit amet.
> - Qui *quodsi iracundia*
> - aliquando id
一开始,我们的文档模型只是
-> document
我们文本的第一行,
> Lorem ipsum dolor
导致 block_quote
块被创建为我们的子块
打开 document
块,和一个 paragraph
块作为子项
这 block_quote
。然后将文本添加到最后打开的
块, paragraph
:
-> document
-> block_quote
-> paragraph
"Lorem ipsum dolor"
下一行,
sit amet.
是开放的“惰性延续” paragraph
,所以它被添加
到该段落的文本:
-> document
-> block_quote
-> paragraph
"Lorem ipsum dolor\nsit amet."
第三行,
> - Qui *quodsi iracundia*
导致 paragraph
要关闭的块,以及一个新的 list
堵塞
作为孩子打开 block_quote
。一个 list_item
也是
作为子项添加 list
,和一个 paragraph
作为一个孩子
这 list_item
。然后将文本添加到新的文本中 paragraph
:
-> document
-> block_quote
paragraph
"Lorem ipsum dolor\nsit amet."
-> list (type=bullet tight=true bullet_char=-)
-> list_item
-> paragraph
"Qui *quodsi iracundia*"
第四行,
> - aliquando id
导致 list_item
(及其孩子 paragraph
)关闭,
和一个新的 list_item
作为孩子打开 list
。一个 paragraph
被添加为新的子项 list_item
,包含文本。
这样我们就得到了最终的树:
-> document
-> block_quote
paragraph
"Lorem ipsum dolor\nsit amet."
-> list (type=bullet tight=true bullet_char=-)
list_item
paragraph
"Qui *quodsi iracundia*"
-> list_item
-> paragraph
"aliquando id"
一旦所有输入都被解析,所有打开的块都会被关闭。
然后我们“遍历树”,访问每个节点,并解析原始数据 段落和标题的字符串内容作为内联。在此 点我们已经看到了所有链接引用定义,所以我们可以 随时解析参考链接。
document
block_quote
paragraph
str "Lorem ipsum dolor"
softbreak
str "sit amet."
list (type=bullet tight=true bullet_char=-)
list_item
paragraph
str "Qui "
emph
str "quodsi iracundia"
list_item
paragraph
str "aliquando id"
请注意 结尾的行 第一段中 是如何
被解析为 softbreak
,以及第一个列表项中的星号
已成为一个 emph
。
到目前为止,内联解析最棘手的部分是处理强调, 强烈的强调、链接和图像。这是使用以下命令完成的 算法。
当我们解析内联时,我们会点击
*
或者 _
字符,或 [
或者 ![
我们插入一个文本节点,其中这些符号作为其文字内容,并且我们 将指向该文本节点的指针添加到 分隔符堆栈 中。
是 定界符栈 一个双向链表。每个 元素包含一个指向文本节点的指针,以及有关
[
, ![
, *
, _
) 当我们击中一个 ]
字符,我们称之为 查找链接或图像
程序(见下文)。
当我们到达输入的末尾时,我们称该 过程为强调
程序(见下文),与 stack_bottom
= 空。
从分隔符堆栈的顶部开始,我们向后看
穿过堆栈寻找一个开口 [
或者 ![
分隔符。
如果找不到,我们将返回一个文字文本节点 ]
。
如果我们确实找到了一个,但它不是 active ,我们会删除 inactive
来自堆栈的分隔符,并返回文字文本节点 ]
。
如果我们找到一个并且它处于活动状态,那么我们会提前解析以查看是否 我们有一个内联链接/图像、参考链接/图像、折叠参考 链接/图像,或快捷方式参考链接/图像。
如果不这样做,那么我们从
分隔符堆栈并返回文字文本节点 ]
。
如果我们这样做,那么
我们返回一个链接或图像节点,其子节点是内联节点 在开始分隔符指向的文本节点之后。
我们 运行流程重点, 对这些内联 [
开场白
作为 stack_bottom
。
我们删除起始分隔符。
如果我们有一个链接(而不是图像),我们还设置所有
[
将开始定界符之前的定界符设为 inactive 。 (这
将阻止我们获取链接中的链接。)
范围 stack_bottom
为我们能走多远设定一个下限
中下降 在定界符堆栈 。如果它是NULL,我们可以
一直走到底部。否则,我们先停下来
来访 stack_bottom
。
让 current_position
指向 分隔符堆栈 上的元素
就在上面 stack_bottom
(或者第一个元素,如果 stack_bottom
为空)。
我们跟踪 openers_bottom
对于每个分隔符
类型 ( *
, _
),索引到结束分隔符运行的长度
(模 3)以及结束分隔符是否也可以是
揭幕战。将此初始化为 stack_bottom
。
然后我们重复以下操作,直到耗尽潜力 闭门器:
移动 current_position
在分隔符堆栈中向前(如果需要)
直到我们找到第一个与定界符更接近的潜在位置 *
或者 _
。
(这将是潜在的最接近的
到输入的开头——解析顺序中的第一个。)
现在,回顾一下堆栈(留在上面 stack_bottom
和
这 openers_bottom
对于此分隔符类型)
第一个匹配的潜在开启符(“匹配”意味着相同的分隔符)。
如果找到:
弄清楚我们是强调还是强烈强调: 如果闭合跨度和开放跨度的长度都 >= 2,我们有 强,否则正常。
相应地插入 emph 或强 emph 节点,之后 与 opener 对应的文本节点。
删除开头符和结束符之间的任何分隔符 分隔符堆栈。
删除 1 个(对于常规 emph)或 2 个(对于强 emph)分隔符
从开始和结束文本节点。如果它们变空
结果,删除它们并删除相应的元素
定界符堆栈。如果关闭节点被移除,则重置
current_position
到堆栈中的下一个元素。
如果没有找到:
放 openers_bottom
到之前的元素 current_position
。
(我们知道这种接近和接近的情况没有开场白
包括这一点,因此这为未来的搜索设置了下限。)
如果越接近于 current_position
不是一个潜在的开场白,
将其从分隔符堆栈中删除(因为我们知道它不能
也可以更接近)。
进步 current_position
到堆栈中的下一个元素。
完成后,我们删除上面的所有分隔符 stack_bottom
从
定界符堆栈。