CommonMark 规范

版本 0.29 (2019-04-06)
John MacFarlane
Creative
   Commons BY-SA
CommonMark 规范John MacFarlane 创作,采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
这是本规范的一个旧版本。最新版本请见 https://spec.commonmark.cn

1介绍

1.1什么是 Markdown?

Markdown 是一种用于编写结构化文档的纯文本格式,基于在电子邮件和 Usenet 帖子中表示格式的惯例。它由 John Gruber 开发(在 Aaron Swartz 的帮助下),并于 2004 年以语法描述和用于将 Markdown 转换为 HTML 的 Perl 脚本 (Markdown.pl) 的形式发布。在接下来的十年里,出现了数十种用不同语言编写的实现。有些在原始 Markdown 语法的基础上增加了脚注、表格和其他文档元素的约定。有些允许将 Markdown 文档渲染为 HTML 以外的格式。Reddit、StackOverflow 和 GitHub 等网站有数以百万计的用户在使用 Markdown。此外,Markdown 开始在 Web 之外使用,用于创作书籍、文章、幻灯片、信件和讲义。

与其他许多通常更容易编写的轻量级标记语法相比,Markdown 的独特之处在于其可读性。正如 Gruber 所写:

Markdown 格式语法的最高设计目标是使其尽可能地易读。其理念是:Markdown 格式的文档应当能以纯文本形式原样发布,而看起来不像被标记语言或格式指令所污染过。(http://daringfireball.net/projects/markdown/

通过将 AsciiDoc 的示例与同等的 Markdown 示例进行比较,可以说明这一点。这是 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 版本要易读得多。列表项的嵌套在源码中清晰可见,而不仅仅是在处理后的文档中。

1.2为什么要制定规范?

John Gruber 的 Markdown 语法权威描述并没有明确定义其语法。以下是一些它未能解答的问题示例:

  1. 子列表需要多少缩进?规范指出续行段落需要缩进四个空格,但对于子列表的描述并不明确。自然会想到它们也必须缩进四个空格,但 Markdown.pl 并不要求这样做。这绝非“边缘情况”,实现之间在此问题上的分歧往往会导致用户在实际文档中遇到意外。(参见 John Gruber 的这条评论。)

  2. 块引用或标题前是否需要空行?大多数实现不需要空行。然而,这可能导致硬换行文本出现意外结果,并在解析时产生歧义(注意有些实现将标题放在块引用内,而另一些则不然)。(John Gruber 也曾表示支持要求空行。)

  3. 缩进代码块前是否需要空行?(Markdown.pl 要求它,但文档中并未提及,且有些实现并不要求。)

    paragraph
        code?
    
  4. 确定列表项何时被 <p> 标签包裹的确切规则是什么?列表可以部分“松散”部分“紧凑”吗?我们该如何处理这样的列表?

    1. one
    
    2. two
    3. three
    

    或者这个?

    1.  one
        - a
    
        - b
    2.  two
    

    (John Gruber 在这里有一些相关的评论。)

  5. 列表标记可以缩进吗?有序列表标记可以右对齐吗?

     8. item 1
     9. item 2
    10. item 2a
    
  6. 这是在第二项中带有主题分割线的一个列表,还是被主题分割线分隔的两个列表?

    * a
    * * * * *
    * b
    
  7. 当列表标记从数字变为圆点时,我们是有两个列表还是一个?(Markdown 语法描述暗示是两个,但 perl 脚本和许多其他实现会生成一个。)

    1. fee
    2. fie
    -  foe
    -  fum
    
  8. 行内结构标记的优先级规则是什么?例如,以下是有效的链接,还是代码片段拥有更高优先级?

    [a backtick (`)](/url) and [another backtick (`)](/url).
    
  9. 强调和加粗标记的优先级规则是什么?例如,以下应如何解析?

    *foo *bar* baz*
    
  10. 块级结构和行内级结构之间的优先级规则是什么?例如,以下应如何解析?

    - `a long code span can contain a hyphen like this
      - and it can screw things up`
    
  11. 列表项可以包含章节标题吗?(Markdown.pl 不允许这样做,但允许块引用包含标题。)

    - # Heading
    
  12. 列表项可以为空吗?

    * a
    *
    * b
    
  13. 链接引用可以在块引用或列表项内定义吗?

    > Blockquote [foo].
    >
    > [foo]: /url
    
  14. 如果有多个同名引用定义,哪个具有优先权?

    [foo]: /url1
    [foo]: /url2
    
    [foo][]
    

在没有规范的情况下,早期的实现者咨询了 Markdown.pl 来解决这些歧义。但 Markdown.pl 存在很多缺陷,在许多情况下会产生明显糟糕的结果,因此它不能令人满意地替代规范。

由于没有明确的规范,各实现之间存在很大分歧。结果,用户经常会惊讶地发现,一个在一个系统(例如 GitHub wiki)上按某种方式渲染的文档,在另一个系统(例如使用 pandoc 转换为 docbook)上渲染方式不同。更糟糕的是,由于 Markdown 中没有任何内容算作“语法错误”,这种分歧往往无法立即被发现。

1.3关于本文档

本文档试图明确地规范 Markdown 语法。它包含了许多 Markdown 和 HTML 并排显示的示例。这些示例旨在兼作一致性测试。随附的脚本 spec_tests.py 可用于对任何 Markdown 程序运行这些测试:

python test/spec_tests.py --spec spec.txt --program PROGRAM

由于本文档描述了如何将 Markdown 解析为抽象语法树,因此使用抽象语法树的抽象表示而非 HTML 更有意义。但 HTML 能够表示我们需要区分的结构,并且为测试选择 HTML 使得在不编写抽象语法树渲染器的情况下对实现进行测试成为可能。

本文档由一个文本文件 spec.txt 生成,该文件以 Markdown 编写,并针对并排测试进行了微小的扩展。脚本 tools/makespec.py 可用于将 spec.txt 转换为 HTML 或 CommonMark(然后可以将其转换为其他格式)。

在示例中,使用 字符来表示制表符。

2预备知识

2.1字符与行

任何字符序列都是有效的 CommonMark 文档。

字符是一个 Unicode 码位。虽然某些码位(例如组合变音符号)在直观意义上不对应于字符,但为了本规范的目的,所有码位都计为字符。

本规范未指定编码;它认为行是由字符而非字节组成的。一致的解析器可能仅限于某种特定的编码。

是零个或多个除换行符 (U+000A) 或回车符 (U+000D) 之外的字符组成的序列,后跟一个行结束符或文件结束符。

行结束符是换行符 (U+000A)、未跟换行符的回车符 (U+000D),或者回车符及其后的换行符。

不包含字符的行,或仅包含空格 (U+0020) 或制表符 (U+0009) 的行,称为空行

本规范将使用以下字符类定义:

空白字符是空格 (U+0020)、制表符 (U+0009)、换行符 (U+000A)、行制表符 (U+000B)、换页符 (U+000C) 或回车符 (U+000D)。

空白是一个或多个空白字符的序列。

Unicode 空白字符是指 Unicode Zs 通用类别中的任何码位,或制表符 (U+0009)、回车符 (U+000D)、换行符 (U+000A) 或换页符 (U+000C)。

Unicode 空白是一个或多个Unicode 空白字符的序列。

空格U+0020

非空白字符是任何不是空白字符的字符。

ASCII 标点符号!, ", #, $, %, &, ', (, ), *, +, ,, -, ., / (U+0021–2F), :, ;, <, =, >, ?, @ (U+003A–0040), [, \, ], ^, _, ` (U+005B–0060), {, |, }, 或 ~ (U+007B–007E)。

标点字符是指 ASCII 标点字符或 Unicode 通用类别 PcPdPePfPiPoPs 中的任何字符。

2.2制表符

行中的制表符不会扩展为空格。然而,在定义块结构的空白环境中,制表符的行为就像被 4 个字符宽度的制表位替换为多个空格一样。

因此,例如,在缩进代码块中可以使用制表符代替四个空格。(注意,内部制表符会按原样传递,不会扩展为空格。)

示例 1尝试一下
→foo→baz→→bim
<pre><code>foo→baz→→bim
</code></pre>
示例 2尝试一下
  →foo→baz→→bim
<pre><code>foo→baz→→bim
</code></pre>
示例 3尝试一下
    a→a
    ὐ→a
<pre><code>a→a
ὐ→a
</code></pre>

在下面的示例中,列表项的续行段落使用制表符缩进;这与使用四个空格缩进的效果完全相同:

示例 4尝试一下
  - foo

→bar
<ul>
<li>
<p>foo</p>
<p>bar</p>
</li>
</ul>
示例 5尝试一下
- foo

→→bar
<ul>
<li>
<p>foo</p>
<pre><code>  bar
</code></pre>
</li>
</ul>

通常,开始块引用的 > 后面可以有一个可选空格,这不被视为内容的一部分。在以下情况下,> 后跟一个制表符,它被视为扩展为三个空格。由于其中一个空格被视为分隔符的一部分,因此在块引用上下文中,foo 被视为缩进了六个空格,所以我们得到了一个以两个空格开头的缩进代码块。

示例 6尝试一下
>→→foo
<blockquote>
<pre><code>  foo
</code></pre>
</blockquote>
示例 7尝试一下
-→→foo
<ul>
<li>
<pre><code>  foo
</code></pre>
</li>
</ul>
示例 8尝试一下
    foo
→bar
<pre><code>foo
bar
</code></pre>
示例 9尝试一下
 - foo
   - bar
→ - baz
<ul>
<li>foo
<ul>
<li>bar
<ul>
<li>baz</li>
</ul>
</li>
</ul>
</li>
</ul>
示例 10尝试一下
#→Foo
<h1>Foo</h1>
示例 11尝试一下
*→*→*→
<hr />

2.3不安全的字符

出于安全考虑,Unicode 字符 U+0000 必须替换为 REPLACEMENT CHARACTER (U+FFFD)。

3块与行内元素

我们可以将文档视为一系列——段落、块引用、列表、标题、分割线和代码块等结构元素。有些块(如块引用和列表项)包含其他块;有些(如标题和段落)包含行内内容——文本、链接、强调文本、图像、代码片段等。

3.1优先级

块结构的指示符总是优先于行内结构的指示符。所以,例如,以下是一个包含两项的列表,而不是一个包含代码片段的项的列表:

示例 12尝试一下
- `one
- two`
<ul>
<li>`one</li>
<li>two`</li>
</ul>

这意味着解析可以分为两步进行:首先,识别文档的块结构;其次,对段落、标题和其他块构造内的文本行进行行内结构解析。第二步需要仅在第一步结束时才可用的链接引用定义信息。注意,第一步需要按顺序处理行,而第二步可以并行化,因为一个块元素的行内解析不会影响任何其他块的行内解析。

3.2容器块与叶子块

我们可以将块分为两种类型:容器块(可以包含其他块)和叶子块(不能包含其他块)。

4叶子块

本节描述了构成 Markdown 文档的不同种类的叶子块。

4.1主题分割线

由 0-3 个空格缩进,后跟三个或更多匹配的 -_* 字符(每个字符后可选跟任意数量的空格或制表符)的行,构成一个主题分割线

示例 13尝试一下
***
---
___
<hr />
<hr />
<hr />

错误的字符

示例 14尝试一下
+++
<p>+++</p>
示例 15尝试一下
===
<p>===</p>

字符不足

示例 16尝试一下
--
**
__
<p>--
**
__</p>

允许一到三个空格的缩进

示例 17尝试一下
 ***
  ***
   ***
<hr />
<hr />
<hr />

四个空格太多了

示例 18尝试一下
    ***
<pre><code>***
</code></pre>
示例 19尝试一下
Foo
    ***
<p>Foo
***</p>

可以使用超过三个字符

示例 20尝试一下
_____________________________________
<hr />

字符之间允许有空格

示例 21尝试一下
 - - -
<hr />
示例 22尝试一下
 **  * ** * ** * **
<hr />
示例 23尝试一下
-     -      -      -
<hr />

末尾允许有空格

示例 24尝试一下
- - - -    
<hr />

然而,行中不能出现其他任何字符

示例 25尝试一下
_ _ _ _ a

a------

---a---
<p>_ _ _ _ a</p>
<p>a------</p>
<p>---a---</p>

要求所有非空白字符必须相同。因此,这不是主题分割线

示例 26尝试一下
 *-*
<p><em>-</em></p>

主题分割线之前或之后不需要空行

示例 27尝试一下
- foo
***
- bar
<ul>
<li>foo</li>
</ul>
<hr />
<ul>
<li>bar</li>
</ul>

主题分割线可以打断段落

示例 28尝试一下
Foo
***
bar
<p>Foo</p>
<hr />
<p>bar</p>

如果一行虚线既符合主题分割线的条件,也可以解释为 Setext 标题的下划线,那么作为 Setext 标题的解释优先。因此,例如,这是一个 Setext 标题,而不是一个段落后跟一个主题分割线

示例 29尝试一下
Foo
---
bar
<h2>Foo</h2>
<p>bar</p>

当主题分割线和列表项都是对一行的可能解释时,主题分割线优先

示例 30尝试一下
* Foo
* * *
* Bar
<ul>
<li>Foo</li>
</ul>
<hr />
<ul>
<li>Bar</li>
</ul>

如果你想在列表项中使用主题分割线,请使用不同的符号

示例 31尝试一下
- Foo
- * * *
<ul>
<li>Foo</li>
<li>
<hr />
</li>
</ul>

4.2ATX 标题

ATX 标题由一串字符组成,解析为行内内容,位于 1-6 个未转义的 # 字符的起始序列和可选的任意数量未转义 # 字符的结束序列之间。起始的 # 字符序列后必须跟一个空格或行尾。可选的结束 # 序列前必须有空格,且后方只能有空格。起始的 # 字符可以缩进 0-3 个空格。标题内容在解析为行内内容之前,会剔除首尾空格。标题级别等于起始序列中 # 字符的数量。

简单的标题

示例 32尝试一下
# foo
## foo
### foo
#### foo
##### foo
###### foo
<h1>foo</h1>
<h2>foo</h2>
<h3>foo</h3>
<h4>foo</h4>
<h5>foo</h5>
<h6>foo</h6>

超过六个 # 字符不是标题

示例 33尝试一下
####### foo
<p>####### foo</p>

除非标题为空,否则 # 字符和标题内容之间至少需要一个空格。注意,许多实现目前并不要求这个空格。但是,最初的 ATX 实现需要这个空格,它有助于防止像下面这样的内容被解析为标题

示例 34尝试一下
#5 bolt

#hashtag
<p>#5 bolt</p>
<p>#hashtag</p>

这不是标题,因为第一个 # 被转义了

示例 35尝试一下
\## foo
<p>## foo</p>

内容按行内元素解析

示例 36尝试一下
# foo *bar* \*baz\*
<h1>foo <em>bar</em> *baz*</h1>

解析行内内容时,会忽略前导和尾随的空白字符

示例 37尝试一下
#                  foo                     
<h1>foo</h1>

允许 1 到 3 个空格的缩进

示例 38尝试一下
 ### foo
  ## foo
   # foo
<h3>foo</h3>
<h2>foo</h2>
<h1>foo</h1>

四个空格太多了

示例 39尝试一下
    # foo
<pre><code># foo
</code></pre>
示例 40尝试一下
foo
    # bar
<p>foo
# bar</p>

结束的 # 字符序列是可选的

示例 41尝试一下
## foo ##
  ###   bar    ###
<h2>foo</h2>
<h3>bar</h3>

它不需要与起始序列长度相同

示例 42尝试一下
# foo ##################################
##### foo ##
<h1>foo</h1>
<h5>foo</h5>

结束序列后允许有空格

示例 43尝试一下
### foo ###     
<h3>foo</h3>

如果 # 字符序列后跟着除空格以外的任何字符,则它不是结束序列,而是被计为标题内容的一部分

示例 44尝试一下
### foo ### b
<h3>foo ### b</h3>

结束序列前必须有一个空格

示例 45尝试一下
# foo#
<h1>foo#</h1>

反斜杠转义的 # 字符不计为结束序列的一部分

示例 46尝试一下
### foo \###
## foo #\##
# foo \#
<h3>foo ###</h3>
<h2>foo ###</h2>
<h1>foo #</h1>

ATX 标题不需要与周围内容由空行分隔,且它们可以打断段落

示例 47尝试一下
****
## foo
****
<hr />
<h2>foo</h2>
<hr />
示例 48尝试一下
Foo bar
# baz
Bar foo
<p>Foo bar</p>
<h1>baz</h1>
<p>Bar foo</p>

ATX 标题可以为空

示例 49尝试一下
## 
#
### ###
<h2></h2>
<h1></h1>
<h3></h3>

4.3Setext 标题

Setext 标题由一行或多行文本组成,每行至少包含一个 非空白字符,缩进不超过 3 个空格,后跟 Setext 标题下划线。这些文本行必须满足以下条件:如果不加下划线,它们会被解析为段落;即它们不能被解析为 代码围栏ATX 标题块引用主题分隔线列表项HTML 区块

一个 Setext 标题下划线是一个由 = 字符或 - 字符组成的序列,缩进不超过 3 个空格,并带有任意数量的尾随空格。如果一行包含单个 - 的字符且可以被解释为一个空的 列表项,则应将其解释为该列表项,而不是 Setext 标题下划线

如果 Setext 标题下划线中使用 = 字符,则该标题为一级标题;如果使用 - 字符,则为二级标题。标题的内容是将前面的文本行解析为 CommonMark 行内内容的结果。

通常,Setext 标题不需要在之前或之后加空行。但是,它不能打断段落,因此当 Setext 标题出现在段落之后时,它们之间需要一个空行。

简单示例

示例 50尝试一下
Foo *bar*
=========

Foo *bar*
---------
<h1>Foo <em>bar</em></h1>
<h2>Foo <em>bar</em></h2>

标题的内容可以跨越多行

示例 51尝试一下
Foo *bar
baz*
====
<h1>Foo <em>bar
baz</em></h1>

内容是将标题的原始内容解析为行内元素的结果。标题的原始内容是通过连接各行并删除首尾的空白字符而形成的。

示例 52尝试一下
  Foo *bar
baz*→
====
<h1>Foo <em>bar
baz</em></h1>

下划线可以是任意长度

示例 53尝试一下
Foo
-------------------------

Foo
=
<h2>Foo</h2>
<h1>Foo</h1>

标题内容最多可以缩进三个空格,且不需要与下划线对齐

示例 54尝试一下
   Foo
---

  Foo
-----

  Foo
  ===
<h2>Foo</h2>
<h2>Foo</h2>
<h1>Foo</h1>

四个空格缩进太多了

示例 55尝试一下
    Foo
    ---

    Foo
---
<pre><code>Foo
---

Foo
</code></pre>
<hr />

Setext 标题下划线最多可以缩进三个空格,并可能包含尾随空格

示例 56尝试一下
Foo
   ----      
<h2>Foo</h2>

四个空格太多了

示例 57尝试一下
Foo
    ---
<p>Foo
---</p>

Setext 标题下划线不能包含内部空格

示例 58尝试一下
Foo
= =

Foo
--- -
<p>Foo
= =</p>
<p>Foo</p>
<hr />

内容行中的尾随空格不会导致换行

示例 59尝试一下
Foo  
-----
<h2>Foo</h2>

结尾的反斜杠也不会导致换行

示例 60尝试一下
Foo\
----
<h2>Foo\</h2>

由于块结构的指示符优先于行内结构的指示符,以下是 Setext 标题

示例 61尝试一下
`Foo
----
`

<a title="a lot
---
of dashes"/>
<h2>`Foo</h2>
<p>`</p>
<h2>&lt;a title=&quot;a lot</h2>
<p>of dashes&quot;/&gt;</p>

Setext 标题下划线不能是列表项或块引用中的惰性续行

示例 62尝试一下
> Foo
---
<blockquote>
<p>Foo</p>
</blockquote>
<hr />
示例 63尝试一下
> foo
bar
===
<blockquote>
<p>foo
bar
===</p>
</blockquote>
示例 64尝试一下
- Foo
---
<ul>
<li>Foo</li>
</ul>
<hr />

段落和其后的 Setext 标题之间需要一个空行,否则段落会成为标题内容的一部分

示例 65尝试一下
Foo
Bar
---
<h2>Foo
Bar</h2>

但总体而言,Setext 标题之前或之后不需要空行

示例 66尝试一下
---
Foo
---
Bar
---
Baz
<hr />
<h2>Foo</h2>
<h2>Bar</h2>
<p>Baz</p>

Setext 标题不能为空

示例 67尝试一下

====
<p>====</p>

Setext 标题文本行不能被解释为除段落以外的块构造。所以,这些示例中的虚线行被解释为主题分割线

示例 68尝试一下
---
---
<hr />
<hr />
示例 69尝试一下
- foo
-----
<ul>
<li>foo</li>
</ul>
<hr />
示例 70尝试一下
    foo
---
<pre><code>foo
</code></pre>
<hr />
示例 71尝试一下
> foo
-----
<blockquote>
<p>foo</p>
</blockquote>
<hr />

如果你想要一个以 > foo 为字面文本的标题,可以使用反斜杠转义

示例 72尝试一下
\> foo
------
<h2>&gt; foo</h2>

兼容性说明:大多数现有的 Markdown 实现不允许 Setext 标题的文本跨越多行。但对于如何解释以下内容,还没有达成共识:

Foo
bar
---
baz

人们可以找到四种不同的解释:

  1. 段落“Foo”,标题“bar”,段落“baz”
  2. 段落“Foo bar”,主题分割线,段落“baz”
  3. 段落“Foo bar — baz”
  4. 标题“Foo bar”,段落“baz”

我们认为第 4 种解释最自然,并且第 4 种解释通过允许跨行标题增加了 CommonMark 的表达能力。希望使用第 1 种解释的作者可以在第一个段落后加一个空行

示例 73尝试一下
Foo

bar
---
baz
<p>Foo</p>
<h2>bar</h2>
<p>baz</p>

希望使用第 2 种解释的作者可以在主题分割线周围加上空行,

示例 74尝试一下
Foo
bar

---

baz
<p>Foo
bar</p>
<hr />
<p>baz</p>

或者使用无法计为 Setext 标题下划线的主题分割线,例如

示例 75尝试一下
Foo
bar
* * *
baz
<p>Foo
bar</p>
<hr />
<p>baz</p>

希望使用第 3 种解释的作者可以使用反斜杠转义

示例 76尝试一下
Foo
bar
\---
baz
<p>Foo
bar
---
baz</p>

4.4缩进代码块

一个 缩进代码块由一个或多个以空行分隔的缩进代码片段组成。一个缩进代码片段是连续的非空行序列,每一行至少缩进四个空格。代码块的内容是行的字面内容,包括结尾的行结束符,减去四个空格的缩进。缩进代码块没有信息字符串

缩进代码块不能打断段落,因此段落和其后的缩进代码块之间必须有一个空行。(但是,代码块和其后的段落之间不需要空行。)

示例 77尝试一下
    a simple
      indented code block
<pre><code>a simple
  indented code block
</code></pre>

如果对缩进的解释存在歧义,既可以解释为代码块,也可以解释为属于列表项的材料,那么列表项的解释优先

示例 78尝试一下
  - foo

    bar
<ul>
<li>
<p>foo</p>
<p>bar</p>
</li>
</ul>
示例 79尝试一下
1.  foo

    - bar
<ol>
<li>
<p>foo</p>
<ul>
<li>bar</li>
</ul>
</li>
</ol>

代码块的内容是字面文本,不会被解析为 Markdown

示例 80尝试一下
    <a/>
    *hi*

    - one
<pre><code>&lt;a/&gt;
*hi*

- one
</code></pre>

这里我们有三个由空行分隔的片段

示例 81尝试一下
    chunk1

    chunk2
  
 
 
    chunk3
<pre><code>chunk1

chunk2



chunk3
</code></pre>

超过四个空格的任何初始空格都将包含在内容中,即使在内部空行中也是如此

示例 82尝试一下
    chunk1
      
      chunk2
<pre><code>chunk1
  
  chunk2
</code></pre>

缩进代码块不能打断段落。(这允许悬挂缩进等。)

示例 83尝试一下
Foo
    bar
<p>Foo
bar</p>

然而,任何前导空格少于四个的非空行都会立即结束代码块。所以一个段落可能会紧接在缩进代码之后

示例 84尝试一下
    foo
bar
<pre><code>foo
</code></pre>
<p>bar</p>

缩进代码可以紧接在其他类型的块之前和之后

示例 85尝试一下
# Heading
    foo
Heading
------
    foo
----
<h1>Heading</h1>
<pre><code>foo
</code></pre>
<h2>Heading</h2>
<pre><code>foo
</code></pre>
<hr />

第一行可以缩进超过四个空格

示例 86尝试一下
        foo
    bar
<pre><code>    foo
bar
</code></pre>

缩进代码块之前或之后的空行不包含在其中

示例 87尝试一下

    
    foo
    
<pre><code>foo
</code></pre>

尾随空格包含在代码块的内容中

示例 88尝试一下
    foo  
<pre><code>foo  
</code></pre>

4.5围栏代码块

一个 代码围栏是一个至少由三个连续的反引号 (`) 或波浪号 (~) 组成的序列。(波浪号和反引号不能混用。)一个 围栏代码块以缩进不超过三个空格的代码围栏开头。

包含代码围栏起始标记的行可以选择在该标记后包含一些文本;这些文本会去除前导和尾随的空白字符,称为信息字符串。如果信息字符串出现在反引号围栏之后,它不能包含任何反引号字符。(设置此限制的原因是,否则某些行内代码会被错误地解释为围栏代码块的开始。)

代码块的内容由所有后续行组成,直到出现与代码块开头相同类型(反引号或波浪号)且至少与起始代码围栏一样长的关闭 代码围栏。如果起始代码围栏缩进了 N 个空格,则每行内容会去除最多 N 个空格的缩进(如果存在)。(如果内容行没有缩进,则保持不变。如果缩进少于 N 个空格,则去除所有缩进。)

关闭代码围栏最多可以缩进三个空格,并且后面只能跟空格,这些空格会被忽略。如果达到了包含块(或文档)的末尾且未找到关闭代码围栏,则代码块包含起始代码围栏之后到包含块(或文档)末尾的所有行。(另一种规范会在未找到关闭代码围栏时要求回溯。但这会使解析效率大打折扣,且这里描述的行为似乎并没有什么真正的弊端。)

围栏代码块可以打断段落,且不需要之前或之后有空行。

代码围栏的内容被视为字面文本,不会被解析为行内元素。信息字符串的第一个单词通常用于指定代码样本的语言,并渲染在 code 标签的 class 属性中。然而,本规范并不强制要求对 信息字符串进行任何特定处理。

这是一个带有反引号的简单示例

示例 89尝试一下
```
<
 >
```
<pre><code>&lt;
 &gt;
</code></pre>

带有波浪号的情况

示例 90尝试一下
~~~
<
 >
~~~
<pre><code>&lt;
 &gt;
</code></pre>

少于三个反引号是不够的

示例 91尝试一下
``
foo
``
<p><code>foo</code></p>

关闭代码围栏必须使用与起始围栏相同的字符

示例 92尝试一下
```
aaa
~~~
```
<pre><code>aaa
~~~
</code></pre>
示例 93尝试一下
~~~
aaa
```
~~~
<pre><code>aaa
```
</code></pre>

关闭代码围栏必须至少与起始围栏一样长

示例 94尝试一下
````
aaa
```
``````
<pre><code>aaa
```
</code></pre>
示例 95尝试一下
~~~~
aaa
~~~
~~~~
<pre><code>aaa
~~~
</code></pre>

未关闭的代码块会由文档(或包含的块引用列表项)末尾关闭

示例 96尝试一下
```
<pre><code></code></pre>
示例 97尝试一下
`````

```
aaa
<pre><code>
```
aaa
</code></pre>
示例 98尝试一下
> ```
> aaa

bbb
<blockquote>
<pre><code>aaa
</code></pre>
</blockquote>
<p>bbb</p>

代码块的内容可以全为空行

示例 99尝试一下
```

  
```
<pre><code>
  
</code></pre>

代码块可以为空

示例 100尝试一下
```
```
<pre><code></code></pre>

围栏可以缩进。如果起始围栏缩进,则内容行中的相应起始缩进将被移除(如果存在)

示例 101尝试一下
 ```
 aaa
aaa
```
<pre><code>aaa
aaa
</code></pre>
示例 102尝试一下
  ```
aaa
  aaa
aaa
  ```
<pre><code>aaa
aaa
aaa
</code></pre>
示例 103尝试一下
   ```
   aaa
    aaa
  aaa
   ```
<pre><code>aaa
 aaa
aaa
</code></pre>

四个空格缩进会产生缩进代码块

示例 104尝试一下
    ```
    aaa
    ```
<pre><code>```
aaa
```
</code></pre>

关闭围栏可以缩进 0-3 个空格,且其缩进无需与起始围栏匹配

示例 105尝试一下
```
aaa
  ```
<pre><code>aaa
</code></pre>
示例 106尝试一下
   ```
aaa
  ```
<pre><code>aaa
</code></pre>

这不是关闭围栏,因为它缩进了 4 个空格

示例 107尝试一下
```
aaa
    ```
<pre><code>aaa
    ```
</code></pre>

代码围栏(起始和关闭)不能包含内部空格

示例 108尝试一下
``` ```
aaa
<p><code> </code>
aaa</p>
示例 109尝试一下
~~~~~~
aaa
~~~ ~~
<pre><code>aaa
~~~ ~~
</code></pre>

围栏代码块可以打断段落,且可以紧接着段落,中间不需要空行

示例 110尝试一下
foo
```
bar
```
baz
<p>foo</p>
<pre><code>bar
</code></pre>
<p>baz</p>

其他块也可以出现在围栏代码块之前和之后,且中间无需空行

示例 111尝试一下
foo
---
~~~
bar
~~~
# baz
<h2>foo</h2>
<pre><code>bar
</code></pre>
<h1>baz</h1>

信息字符串 可以提供在起始代码围栏之后。虽然本规范没有强制要求对信息字符串进行任何特定处理,但第一个单词通常用于指定代码块的语言。在 HTML 输出中,语言通常通过向 code 元素添加一个由 language- 后跟语言名称组成的类来指示。

示例 112尝试一下
```ruby
def foo(x)
  return 3
end
```
<pre><code class="language-ruby">def foo(x)
  return 3
end
</code></pre>
示例 113尝试一下
~~~~    ruby startline=3 $%@#$
def foo(x)
  return 3
end
~~~~~~~
<pre><code class="language-ruby">def foo(x)
  return 3
end
</code></pre>
示例 114尝试一下
````;
````
<pre><code class="language-;"></code></pre>

反引号代码块的 信息字符串不能包含反引号

示例 115尝试一下
``` aa ```
foo
<p><code>aa</code>
foo</p>

波浪号代码块的信息字符串可以包含反引号和波浪号

示例 116尝试一下
~~~ aa ``` ~~~
foo
~~~
<pre><code class="language-aa">foo
</code></pre>

关闭代码围栏不能包含 信息字符串

示例 117尝试一下
```
``` aaa
```
<pre><code>``` aaa
</code></pre>

4.6HTML 块

一个 HTML 块是一组被视为原生 HTML(且不会在 HTML 输出中转义)的行。

HTML 块有七种类型,由它们的开始和结束条件定义。块以符合开始条件的行开始(最多有三个空格的缩进)。它在随后的第一个符合匹配结束条件的行处结束,或者在文档的最后一行结束,或者如果未遇到符合[结束条件]的行,则在包含当前 HTML 块的容器块的最后一行结束。如果第一行既满足开始条件又满足[结束条件],则该块仅包含这一行。

  1. 开始条件:行以字符串 <script, <pre, 或 <style 开头(不区分大小写),后跟空白、字符串 > 或行尾。
    结束条件:行包含结束标签 </script>, </pre>, 或 </style>(不区分大小写;无需与开始标签匹配)。

  2. 开始条件:行以字符串 <!-- 开头。
    结束条件:行包含字符串 -->

  3. 开始条件:行以字符串 <? 开头。
    结束条件:行包含字符串 ?>

  4. 开始条件:行以字符串 <! 开头,后跟一个大写 ASCII 字母。
    结束条件:行包含字符 >

  5. 开始条件:行以字符串 <![CDATA[ 开头。
    结束条件:行包含字符串 ]]>

  6. 开始条件:行以 <</ 字符串开头,后跟以下字符串之一(不区分大小写):addressarticleasidebasebasefontblockquotebodycaptioncentercolcolgroupdddetailsdialogdirdivdldtfieldsetfigcaptionfigurefooterformframeframeseth1h2h3h4h5h6headheaderhrhtmliframelegendlilinkmainmenumenuitemnavnoframesoloptgroupoptionpparamsectionsourcesummarytabletbodytdtfootththeadtitletrtrackul,后跟空白字符、行尾、> 字符串或 /> 字符串。
    结束条件:行后跟一个空行

  7. 开始条件:行以完整的开始标签tag name 不是 scriptstylepre)或完整的结束标签开头,后跟仅为空白字符或行尾。
    结束条件:行后跟一个空行

HTML 块持续到被其相应的[结束条件]、文档的最后一行或其他容器块关闭为止。这意味着HTML 块内任何本可能被识别为开始条件的 HTML 都将被解析器忽略,并原样通过,而不会改变解析器的状态。

例如,由 <table> 开始的 HTML 块中的 <pre> 不会影响解析器状态;由于该 HTML 块是由开始条件 6 启动的,它将在任何空白行处结束。这可能会令人意外。

示例 118尝试一下
<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 块。)

下面是一些简单示例。这里是一些基本的第 6 类 HTML 块

示例 119尝试一下
<table>
  <tr>
    <td>
           hi
    </td>
  </tr>
</table>

okay.
<table>
  <tr>
    <td>
           hi
    </td>
  </tr>
</table>
<p>okay.</p>
示例 120尝试一下
 <div>
  *hello*
         <foo><a>
 <div>
  *hello*
         <foo><a>

块也可以以结束标签开头

示例 121尝试一下
</div>
*foo*
</div>
*foo*

这里我们有两个 HTML 块,中间有一个 Markdown 段落

示例 122尝试一下
<DIV CLASS="foo">

*Markdown*

</DIV>
<DIV CLASS="foo">
<p><em>Markdown</em></p>
</DIV>

第一行的标签可以是部分的,只要它在有空白的地方被分割即可

示例 123尝试一下
<div id="foo"
  class="bar">
</div>
<div id="foo"
  class="bar">
</div>
示例 124尝试一下
<div id="foo" class="bar
  baz">
</div>
<div id="foo" class="bar
  baz">
</div>

开始标签不需要关闭

示例 125尝试一下
<div>
*foo*

*bar*
<div>
*foo*
<p><em>bar</em></p>

部分标签甚至不需要完整(垃圾进,垃圾出)

示例 126尝试一下
<div id="foo"
*hi*
<div id="foo"
*hi*
示例 127尝试一下
<div class
foo
<div class
foo

初始标签甚至不需要是有效标签,只要它以标签的样子开始即可

示例 128尝试一下
<div *???-&&&-<---
*foo*
<div *???-&&&-<---
*foo*

在第 6 类块中,初始标签不需要在单独的一行上

示例 129尝试一下
<div><a href="bar">*foo*</a></div>
<div><a href="bar">*foo*</a></div>
示例 130尝试一下
<table><tr><td>
foo
</td></tr></table>
<table><tr><td>
foo
</td></tr></table>

直到下一个空行或文档末尾的所有内容都包含在 HTML 块中。因此,在以下示例中,看起来像 Markdown 代码块的内容实际上是 HTML 块的一部分,该块将持续到空行或到达文档末尾

示例 131尝试一下
<div></div>
``` c
int x = 33;
```
<div></div>
``` c
int x = 33;
```

要以 不在 (6) 中的块级标签列表中的标签开始 HTML 块,必须将该标签放在第一行的单独一行上(并且它必须是完整的)

示例 132尝试一下
<a href="foo">
*bar*
</a>
<a href="foo">
*bar*
</a>

在第 7 类块中,标签名可以是任何东西

示例 133尝试一下
<Warning>
*bar*
</Warning>
<Warning>
*bar*
</Warning>
示例 134尝试一下
<i class="foo">
*bar*
</i>
<i class="foo">
*bar*
</i>
示例 135尝试一下
</ins>
*bar*
</ins>
*bar*

这些规则旨在让我们能够处理既可以作为块级标签也可以作为行内级标签的标签。<del> 标签就是一个很好的例子。我们可以用三种不同的方式用 <del> 标签包裹内容。在这种情况下,我们得到了一个原生 HTML 块,因为 <del> 标签单独占一行

示例 136尝试一下
<del>
*foo*
</del>
<del>
*foo*
</del>

在这种情况下,我们得到了一个仅包含 <del> 标签的原生 HTML 块(因为它以随后的空行结束)。所以内容会被解释为 CommonMark

示例 137尝试一下
<del>

*foo*

</del>
<del>
<p><em>foo</em></p>
</del>

最后,在这种情况下,<del> 标签被解释为 CommonMark 段落 内部原生 HTML。(因为标签没有单独占一行,我们得到的是行内 HTML 而不是 HTML 块。)

示例 138尝试一下
<del>*foo*</del>
<p><del><em>foo</em></del></p>

设计为包含字面内容(script, style, pre)、注释、处理指令和声明的 HTML 标签的处理方式略有不同。这些块不是在第一个空行处结束,而是在包含相应结束标签的第一行结束。因此,这些块可以包含空行

pre 标签(第 1 类)

示例 139尝试一下
<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>

script 标签(第 1 类)

示例 140尝试一下
<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>

style 标签(第 1 类)

示例 141尝试一下
<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>

如果没有匹配的结束标签,该块将在文档(或包含的块引用列表项)末尾结束

示例 142尝试一下
<style
  type="text/css">

foo
<style
  type="text/css">

foo
示例 143尝试一下
> <div>
> foo

bar
<blockquote>
<div>
foo
</blockquote>
<p>bar</p>
示例 144尝试一下
- <div>
- foo
<ul>
<li>
<div>
</li>
<li>foo</li>
</ul>

结束标签可以出现在与开始标签同一行上

示例 145尝试一下
<style>p{color:red;}</style>
*foo*
<style>p{color:red;}</style>
<p><em>foo</em></p>
示例 146尝试一下
<!-- foo -->*bar*
*baz*
<!-- foo -->*bar*
<p><em>baz</em></p>

注意,最后一行中结束标签之后的任何内容都将包含在 HTML 块

示例 147尝试一下
<script>
foo
</script>1. *bar*
<script>
foo
</script>1. *bar*

注释(第 2 类)

示例 148尝试一下
<!-- Foo

bar
   baz -->
okay
<!-- Foo

bar
   baz -->
<p>okay</p>

处理指令(第 3 类)

示例 149尝试一下
<?php

  echo '>';

?>
okay
<?php

  echo '>';

?>
<p>okay</p>

声明(第 4 类)

示例 150尝试一下
<!DOCTYPE html>
<!DOCTYPE html>

CDATA(第 5 类)

示例 151尝试一下
<![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-3 个空格,但不能缩进 4 个

示例 152尝试一下
  <!-- foo -->

    <!-- foo -->
  <!-- foo -->
<pre><code>&lt;!-- foo --&gt;
</code></pre>
示例 153尝试一下
  <div>

    <div>
  <div>
<pre><code>&lt;div&gt;
</code></pre>

第 1–6 类的 HTML 块可以打断段落,且不需要之前有空行。

示例 154尝试一下
Foo
<div>
bar
</div>
<p>Foo</p>
<div>
bar
</div>

然而,需要一个随后的空行,除非是在文档末尾,并且除了上述 1-5 类型的块之外

示例 155尝试一下
<div>
bar
</div>
*foo*
<div>
bar
</div>
*foo*

第 7 类 HTML 块不能打断段落

示例 156尝试一下
Foo
<a href="bar">
baz
<p>Foo
<a href="bar">
baz</p>

此规则与 John Gruber 原来的 Markdown 语法规范不同,后者指出:

唯一的限制是块级 HTML 元素(例如 <div>, <table>, <pre>, <p> 等)必须与周围内容用空行分隔,且该块的开始和结束标签不应使用制表符或空格缩进。

在某些方面,Gruber 的规则比这里给出的规则更严格:

大多数 Markdown 实现(包括 Gruber 自己的一些实现)并不遵循所有这些限制。

然而,在有一个方面,Gruber 的规则比这里给出的规则更宽松,因为它允许 HTML 块内出现空行。这里禁止它们有两个原因。首先,它消除了解析平衡标签的需要,这很昂贵,并且如果未找到匹配的结束标签,可能需要从文档末尾回溯。其次,它提供了一种在 HTML 标签内包含 Markdown 内容的非常简单且灵活的方法:只需使用空行将 Markdown 与 HTML 分隔开。

比较:

示例 157尝试一下
<div>

*Emphasized* text.

</div>
<div>
<p><em>Emphasized</em> text.</p>
</div>
示例 158尝试一下
<div>
*Emphasized* text.
</div>
<div>
*Emphasized* text.
</div>

一些 Markdown 实现采用了如果开始标签具有 markdown=1 属性就将标签内内容解释为文本的约定。上述规则似乎是一种更简单、更优雅的实现相同表达能力的方法,解析起来也简单得多。

主要潜在的缺点是人们无法再 100% 可靠地将 HTML 块粘贴到 Markdown 文档中。但是,在大多数情况下这可以正常工作,因为 HTML 中的空行通常后跟 HTML 块标签。例如:

示例 159尝试一下
<table>

<tr>

<td>
Hi
</td>

</tr>

</table>
<table>
<tr>
<td>
Hi
</td>
</tr>
</table>

但是,如果内部标签缩进 被空格分隔,则会出现问题,因为那样它们会被解释为缩进代码块

示例 160尝试一下
<table>

  <tr>

    <td>
      Hi
    </td>

  </tr>

</table>
<table>
  <tr>
<pre><code>&lt;td&gt;
  Hi
&lt;/td&gt;
</code></pre>
  </tr>
</table>

幸运的是,空行通常是不必要的,可以删除。例外情况是在 <pre> 标签内,但如上文所述,以 <pre> 开头的原生 HTML 块确实可以包含空行。

一个 链接引用定义由一个链接标签组成,缩进不超过三个空格,后跟一个冒号 (:),可选的空白(包括最多一个行结束符),一个链接目标,可选的空白(包括最多一个行结束符),以及一个可选的链接标题,如果存在,必须用空白链接目标分隔。该行不能再出现其他非空白字符

一个 链接引用定义不对应于文档的结构元素。相反,它定义了一个可在文档中其他地方的引用链接和引用式图像中使用的标签。链接引用定义可以出现在使用它们的链接之前或之后。

示例 161尝试一下
[foo]: /url "title"

[foo]
<p><a href="/url" title="title">foo</a></p>
示例 162尝试一下
   [foo]: 
      /url  
           'the title'  

[foo]
<p><a href="/url" title="the title">foo</a></p>
示例 163尝试一下
[Foo*bar\]]:my_(url) 'title (with parens)'

[Foo*bar\]]
<p><a href="my_(url)" title="title (with parens)">Foo*bar]</a></p>
示例 164尝试一下
[Foo bar]:
<my url>
'title'

[Foo bar]
<p><a href="my%20url" title="title">Foo bar</a></p>

标题可以跨越多行

示例 165尝试一下
[foo]: /url '
title
line1
line2
'

[foo]
<p><a href="/url" title="
title
line1
line2
">foo</a></p>

然而,它不能包含空行

示例 166尝试一下
[foo]: /url 'title

with blank line'

[foo]
<p>[foo]: /url 'title</p>
<p>with blank line'</p>
<p>[foo]</p>

标题可以省略

示例 167尝试一下
[foo]:
/url

[foo]
<p><a href="/url">foo</a></p>

链接目标不能省略

示例 168尝试一下
[foo]:

[foo]
<p>[foo]:</p>
<p>[foo]</p>

然而,可以使用尖括号指定一个空的链接目标

示例 169尝试一下
[foo]: <>

[foo]
<p><a href="">foo</a></p>

标题必须与链接目标通过空白字符分隔。

示例 170尝试一下
[foo]: <bar>(baz)

[foo]
<p>[foo]: <bar>(baz)</p>
<p>[foo]</p>

标题和目标都可以包含反斜杠转义和字面反斜杠

示例 171尝试一下
[foo]: /url\bar\*baz "foo\"bar\baz"

[foo]
<p><a href="/url%5Cbar*baz" title="foo&quot;bar\baz">foo</a></p>

链接可以出现在其对应的定义之前

示例 172尝试一下
[foo]

[foo]: url
<p><a href="url">foo</a></p>

如果有多个匹配的定义,第一个具有优先权

示例 173尝试一下
[foo]

[foo]: first
[foo]: second
<p><a href="first">foo</a></p>

链接一节所述,标签匹配是不区分大小写的(参见 matches)。

示例 174尝试一下
[FOO]: /url

[Foo]
<p><a href="/url">Foo</a></p>
示例 175尝试一下
[ΑΓΩ]: /φου

[αγω]
<p><a href="/%CF%86%CE%BF%CF%85">αγω</a></p>

这是一个没有对应链接的链接引用定义。它对文档没有任何贡献。

示例 176尝试一下
[foo]: /url

这里是另一个

示例 177尝试一下
[
foo
]: /url
bar
<p>bar</p>

这不是链接引用定义,因为标题后面有非空白字符

示例 178尝试一下
[foo]: /url "title" ok
<p>[foo]: /url &quot;title&quot; ok</p>

这是一个链接引用定义,但它没有标题

示例 179尝试一下
[foo]: /url
"title" ok
<p>&quot;title&quot; ok</p>

这不是链接引用定义,因为它缩进了四个空格

示例 180尝试一下
    [foo]: /url "title"

[foo]
<pre><code>[foo]: /url &quot;title&quot;
</code></pre>
<p>[foo]</p>

这不是一个链接引用定义,因为它出现在代码块内部

示例 181尝试一下
```
[foo]: /url
```

[foo]
<pre><code>[foo]: /url
</code></pre>
<p>[foo]</p>

链接引用定义不能中断段落。

示例 182尝试一下
Foo
[bar]: /baz

[bar]
<p>Foo
[bar]: /baz</p>
<p>[bar]</p>

但是,它可以直接跟在其他块元素之后,例如标题和主题分隔符,并且不需要后跟空行。

示例 183尝试一下
# [Foo]
[foo]: /url
> bar
<h1><a href="/url">Foo</a></h1>
<blockquote>
<p>bar</p>
</blockquote>
示例 184尝试一下
[foo]: /url
bar
===
[foo]
<h1>bar</h1>
<p><a href="/url">foo</a></p>
示例 185尝试一下
[foo]: /url
===
[foo]
<p>===
<a href="/url">foo</a></p>

多个链接引用定义可以彼此连续出现,无需中间空行。

示例 186尝试一下
[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>

链接引用定义可以出现在块容器(如列表和引用块)内部。它们影响整个文档,而不仅仅是定义它们的那个容器。

示例 187尝试一下
[foo]

> [foo]: /url
<p><a href="/url">foo</a></p>
<blockquote>
</blockquote>

某物是否为链接引用定义,与它定义的链接引用是否在文档中使用无关。因此,例如,以下文档仅包含一个链接引用定义,没有可见内容

示例 188尝试一下
[foo]: /url

4.8段落

一系列不能被解释为其他类型块的非空行构成了一个段落。段落的内容是对段落原始内容进行行内解析的结果。段落的原始内容是通过连接各行并去除首尾的空白字符形成的。

一个有两个段落的简单示例

示例 189尝试一下
aaa

bbb
<p>aaa</p>
<p>bbb</p>

段落可以包含多行,但不能包含空行

示例 190尝试一下
aaa
bbb

ccc
ddd
<p>aaa
bbb</p>
<p>ccc
ddd</p>

段落之间的多个空行无效

示例 191尝试一下
aaa


bbb
<p>aaa</p>
<p>bbb</p>

前导空格会被忽略

示例 192尝试一下
  aaa
 bbb
<p>aaa
bbb</p>

第一行之后的各行可以有任意数量的缩进,因为缩进代码块不能中断段落。

示例 193尝试一下
aaa
             bbb
                                       ccc
<p>aaa
bbb
ccc</p>

然而,第一行的缩进最多只能有三个空格,否则会触发缩进代码块

示例 194尝试一下
   aaa
bbb
<p>aaa
bbb</p>
示例 195尝试一下
    aaa
bbb
<pre><code>aaa
</code></pre>
<p>bbb</p>

行尾空格在行内解析前会被剔除,因此以两个或更多空格结尾的段落不会以 硬换行 结尾

示例 196尝试一下
aaa     
bbb     
<p>aaa<br />
bbb</p>

4.9空行

块级元素之间的空行会被忽略,但在确定列表紧凑还是松散时起作用。

文档开头和结尾的空行也会被忽略。

示例 197尝试一下
  

aaa
  

# aaa

  
<p>aaa</p>
<h1>aaa</h1>

5容器块

容器块是包含其他块作为其内容的块。有两种基本的容器块:引用块列表项列表列表项的元容器。

我们以递归方式定义容器块的语法。定义的一般形式是

如果 X 是一系列块,那么以某种方式转换 X 的结果就是类型为 Y 的容器,其内容为这些块。

因此,我们通过解释如何从其内容中生成这些块来解释什么是引用块或列表项。这足以定义语法,尽管它没有提供解析这些构造的步骤(解析策略在下文解析策略部分提供)。

5.1块引用

引用块标记由 0-3 个初始缩进空格,加上 (a) 字符 > 及其后的一个空格,或 (b) 一个字符 > 且其后没有空格组成。

以下规则定义了引用块

  1. 基本情况。 如果一行字符串 Ls 构成一系列块 Bs,那么在 Ls 中每一行的开头添加一个引用块标记的结果就是一个包含 Bs引用块

  2. 惰性匹配。 如果一行字符串 Ls 构成一个内容为 Bs引用块,那么如果从一行或多行中删除初始引用块标记,且该行中标记后的下一个非空白字符段落延续文本,其结果仍是一个内容为 Bs 的引用块。段落延续文本是指将被解析为段落内容一部分,但不在段落开头的文本。

  3. 连续性。 如果两个引用块之间没有空行,文档不能包含两个连续的引用块。

除此之外的其他内容均不视为引用块

这是一个简单的例子

示例 198尝试一下
> # Foo
> bar
> baz
<blockquote>
<h1>Foo</h1>
<p>bar
baz</p>
</blockquote>

可以省略 > 字符后的空格

示例 199尝试一下
># Foo
>bar
> baz
<blockquote>
<h1>Foo</h1>
<p>bar
baz</p>
</blockquote>

> 字符可以缩进 1-3 个空格

示例 200尝试一下
   > # Foo
   > bar
 > baz
<blockquote>
<h1>Foo</h1>
<p>bar
baz</p>
</blockquote>

四个空格会产生一个代码块

示例 201尝试一下
    > # Foo
    > bar
    > baz
<pre><code>&gt; # Foo
&gt; bar
&gt; baz
</code></pre>

懒惰性条款允许我们省略段落续行文本前的 >

示例 202尝试一下
> # Foo
> bar
baz
<blockquote>
<h1>Foo</h1>
<p>bar
baz</p>
</blockquote>

引用块可以包含一些惰性匹配行和一些非惰性匹配行

示例 203尝试一下
> bar
baz
> foo
<blockquote>
<p>bar
baz
foo</p>
</blockquote>

懒惰性仅适用于如果加上块引用标记本将成为段落续行的行。例如,在以下第二行中不能省略 >

> foo
> ---

否则会改变含义

示例 204尝试一下
> foo
---
<blockquote>
<p>foo</p>
</blockquote>
<hr />

同样,如果我们省略以下第二行中的 >

> - foo
> - bar

那么引用块在第一行之后结束

示例 205尝试一下
> - foo
- bar
<blockquote>
<ul>
<li>foo</li>
</ul>
</blockquote>
<ul>
<li>bar</li>
</ul>

出于同样的原因,我们不能省略缩进代码块或围栏代码块后续行前面的 >

示例 206尝试一下
>     foo
    bar
<blockquote>
<pre><code>foo
</code></pre>
</blockquote>
<pre><code>bar
</code></pre>
示例 207尝试一下
> ```
foo
```
<blockquote>
<pre><code></code></pre>
</blockquote>
<p>foo</p>
<pre><code></code></pre>

注意在以下情况下,我们有一个懒惰续行

示例 208尝试一下
> foo
    - bar
<blockquote>
<p>foo
- bar</p>
</blockquote>

为了理解原因,请注意:在

> foo
>     - bar

- bar 缩进太多无法开始列表,且不能是缩进代码块,因为缩进代码块不能中断段落,所以它是段落续行文本

引用块可以为空

示例 209尝试一下
>
<blockquote>
</blockquote>
示例 210尝试一下
>
>  
> 
<blockquote>
</blockquote>

引用块可以有初始或最终空行

示例 211尝试一下
>
> foo
>  
<blockquote>
<p>foo</p>
</blockquote>

空行总是会分隔引用块

示例 212尝试一下
> foo

> bar
<blockquote>
<p>foo</p>
</blockquote>
<blockquote>
<p>bar</p>
</blockquote>

(大多数当前的 Markdown 实现,包括 John Gruber 最初的 Markdown.pl,会将此示例解析为一个包含两个段落的单个引用块。但让作者决定想要两个还是一个引用块似乎更好。)

连续性意味着如果我们把这些引用块放在一起,我们就会得到一个单一的引用块

示例 213尝试一下
> foo
> bar
<blockquote>
<p>foo
bar</p>
</blockquote>

要获得包含两个段落的引用块,请使用

示例 214尝试一下
> foo
>
> bar
<blockquote>
<p>foo</p>
<p>bar</p>
</blockquote>

引用块可以中断段落

示例 215尝试一下
foo
> bar
<p>foo</p>
<blockquote>
<p>bar</p>
</blockquote>

通常情况下,引用块前后不需要空行

示例 216尝试一下
> aaa
***
> bbb
<blockquote>
<p>aaa</p>
</blockquote>
<hr />
<blockquote>
<p>bbb</p>
</blockquote>

然而,由于惰性,在引用块和随后的段落之间需要一个空行

示例 217尝试一下
> bar
baz
<blockquote>
<p>bar
baz</p>
</blockquote>
示例 218尝试一下
> bar

baz
<blockquote>
<p>bar</p>
</blockquote>
<p>baz</p>
示例 219尝试一下
> bar
>
baz
<blockquote>
<p>bar</p>
</blockquote>
<p>baz</p>

惰性规则的一个结果是,在嵌套引用块的延续行上可以省略任意数量的初始 >

示例 220尝试一下
> > > foo
bar
<blockquote>
<blockquote>
<blockquote>
<p>foo
bar</p>
</blockquote>
</blockquote>
</blockquote>
示例 221尝试一下
>>> foo
> bar
>>baz
<blockquote>
<blockquote>
<blockquote>
<p>foo
bar
baz</p>
</blockquote>
</blockquote>
</blockquote>

当在引用块中包含缩进代码块时,请记住引用块标记包括 > 及其后的一个空格。因此 > 之后需要五个空格

示例 222尝试一下
>     code

>    not code
<blockquote>
<pre><code>code
</code></pre>
</blockquote>
<blockquote>
<p>not code</p>
</blockquote>

5.2列表项

列表标记无序列表标记有序列表标记

无序列表标记-, +* 字符。

有序列表标记是由 1–9 位阿拉伯数字 (0-9) 组成的序列,后跟 .) 字符。(长度限制的原因是 10 位数字在某些浏览器中会出现整数溢出。)

以下规则定义了列表项

  1. 基本情况。如果一系列行 Ls 构成一系列以非空白字符开头的块 Bs,且 M 是宽度为 W 的列表标记,后跟 1 ≤ N ≤ 4 个空格,则在 Ls 的第一行前添加 M 和随后的空格,并将 Ls 的后续行缩进 W + N 个空格的结果,就是一个包含 Bs 内容的列表项。列表项的类型(无序或有序)由其列表标记的类型决定。如果列表项是有序的,它还会根据有序列表标记被分配一个起始数字。

    例外

    1. 列表中的第一个列表项中断段落时(即,它开始于本应计为段落续行文本的行上),那么 (a) 行 Ls 不得以空行开始,并且 (b) 如果列表项是有序的,起始编号必须为 1。
    2. 如果任何行是主题分隔符,则该行不是列表项。

例如,设 Ls 为以下几行

示例 223尝试一下
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 相同

示例 224尝试一下
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>

最需要注意的是,列表标记之后的文本位置决定了列表项中后续块所需的缩进量。如果列表标记占用两个空格,并且列表标记与下一个非空白字符之间有三个空格,则块必须缩进五个空格才能被归入该列表项。

以下是一些显示内容必须缩进多少才能置于列表项之下的示例

示例 225尝试一下
- one

 two
<ul>
<li>one</li>
</ul>
<p>two</p>
示例 226尝试一下
- one

  two
<ul>
<li>
<p>one</p>
<p>two</p>
</li>
</ul>
示例 227尝试一下
 -    one

     two
<ul>
<li>one</li>
</ul>
<pre><code> two
</code></pre>
示例 228尝试一下
 -    one

      two
<ul>
<li>
<p>one</p>
<p>two</p>
</li>
</ul>

人们很容易从列的角度来考虑这个问题:延续块必须至少缩进到列表标记之后第一个非空白字符所在的列。然而,这并不完全正确。列表标记之后的空格决定了需要多少相对缩进。此缩进到达哪一列将取决于列表项如何嵌入其他构造中,如该示例所示

示例 229尝试一下
   > > 1.  one
>>
>>     two
<blockquote>
<blockquote>
<ol>
<li>
<p>one</p>
<p>two</p>
</li>
</ol>
</blockquote>
</blockquote>

在这里,two 出现在与列表标记 1. 相同的列中,但实际上被包含在列表项中,因为在最后一个包含的引用块标记之后有足够的缩进。

反之亦然。在以下示例中,单词 two 出现在列表项初始文本 one 的远右侧,但它不被视为列表项的一部分,因为它在引用块标记之后的缩进不足

示例 230尝试一下
>>- one
>>
  >  > two
<blockquote>
<blockquote>
<ul>
<li>one</li>
</ul>
<p>two</p>
</blockquote>
</blockquote>

注意,列表标记和随后的任何内容之间至少需要一个空格,因此以下不是列表项

示例 231尝试一下
-one

2.two
<p>-one</p>
<p>2.two</p>

列表项可以包含由超过一个空行分隔的块。

示例 232尝试一下
- foo


  bar
<ul>
<li>
<p>foo</p>
<p>bar</p>
</li>
</ul>

列表项可以包含任何类型的块

示例 233尝试一下
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>

包含缩进代码块的列表项将逐字保留代码块内的空行。

示例 234尝试一下
- Foo

      bar


      baz
<ul>
<li>
<p>Foo</p>
<pre><code>bar


baz
</code></pre>
</li>
</ul>

注意,有序列表的起始编号必须为九位数字或更少

示例 235尝试一下
123456789. ok
<ol start="123456789">
<li>ok</li>
</ol>
示例 236尝试一下
1234567890. not ok
<p>1234567890. not ok</p>

起始编号可以以 0 开头

示例 237尝试一下
0. ok
<ol start="0">
<li>ok</li>
</ol>
示例 238尝试一下
003. ok
<ol start="3">
<li>ok</li>
</ol>

起始编号不能为负数

示例 239尝试一下
-1. not ok
<p>-1. not ok</p>
  1. 以缩进代码开头的项。如果一系列行 Ls 构成一系列以缩进代码块开头的块 Bs,且 M 是宽度为 W 的列表标记,后跟一个空格,则在 Ls 的第一行前添加 M 和随后的空格,并将 Ls 的后续行缩进 W + 1 个空格的结果,就是一个包含 Bs 内容的列表项。如果某行为空,则无需缩进。列表项的类型(无序或有序)由其列表标记的类型决定。如果列表项是有序的,它还会根据有序列表标记被分配一个起始数字。

缩进代码块需要缩进到列表项中包含文本区域边缘之外的四个空格。在下一种情况下,即为 6 个空格

示例 240尝试一下
- foo

      bar
<ul>
<li>
<p>foo</p>
<pre><code>bar
</code></pre>
</li>
</ul>

在这种情况下为 11 个空格

示例 241尝试一下
  10.  foo

           bar
<ol start="10">
<li>
<p>foo</p>
<pre><code>bar
</code></pre>
</li>
</ol>

如果列表项中的第一个块是缩进代码块,则根据规则 #2,其内容必须在列表标记之后缩进一个空格

示例 242尝试一下
    indented code

paragraph

    more code
<pre><code>indented code
</code></pre>
<p>paragraph</p>
<pre><code>more code
</code></pre>
示例 243尝试一下
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>

注意,额外的空格缩进会被解释为代码块内的空格

示例 244尝试一下
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) 以缩进代码块开头的情况。在如下情况中,第一块以三个空格缩进开头,规则不允许通过缩进整体并在前面预置列表标记来形成列表项

示例 245尝试一下
   foo

bar
<p>foo</p>
<p>bar</p>
示例 246尝试一下
-    foo

  bar
<ul>
<li>foo</li>
</ul>
<p>bar</p>

这不是一个显著的限制,因为当一个块以 1-3 个空格缩进开头时,缩进总是可以移除而不改变解释,从而允许应用规则 #1。所以,在上述情况下

示例 247尝试一下
-  foo

   bar
<ul>
<li>
<p>foo</p>
<p>bar</p>
</li>
</ul>
  1. 以空行开头的项。 如果一行序列 Ls 以单个空行开头,构成一系列(可能是空的)块 Bs,且彼此之间不被超过一个空行分隔;且 M 是一个宽度为 W 的列表标记,那么将 M 预置到 Ls 的第一行,并将 Ls 的后续行缩进 W + 1 个空格的结果,就是一个以 Bs 为内容的列表项。如果一行是空的,则不需要缩进。列表项的类型(无序或有序)由其列表标记的类型决定。如果列表项是有序的,则还会根据有序列表标记分配一个起始编号。

以下是一些以空行开头但不为空的列表项

示例 248尝试一下
-
  foo
-
  ```
  bar
  ```
-
      baz
<ul>
<li>foo</li>
<li>
<pre><code>bar
</code></pre>
</li>
<li>
<pre><code>baz
</code></pre>
</li>
</ul>

当列表项以空行开始时,列表标记后的空格数量不会改变所需的缩进量

示例 249尝试一下
-   
  foo
<ul>
<li>foo</li>
</ul>

列表项最多可以以一个空行开头。在以下示例中,foo 不是列表项的一部分

示例 250尝试一下
-

  foo
<ul>
<li></li>
</ul>
<p>foo</p>

这是一个空的无序列表项

示例 251尝试一下
- foo
-
- bar
<ul>
<li>foo</li>
<li></li>
<li>bar</li>
</ul>

列表标记之后是否有空格无关紧要

示例 252尝试一下
- foo
-   
- bar
<ul>
<li>foo</li>
<li></li>
<li>bar</li>
</ul>

这是一个空的有序列表项

示例 253尝试一下
1. foo
2.
3. bar
<ol>
<li>foo</li>
<li></li>
<li>bar</li>
</ol>

列表可以以空的列表项开始或结束

示例 254尝试一下
*
<ul>
<li></li>
</ul>

然而,空列表项不能中断段落

示例 255尝试一下
foo
*

foo
1.
<p>foo
*</p>
<p>foo
1.</p>
  1. 缩进。 如果一行序列 Ls 根据规则 #1、#2 或 #3 构成一个列表项,那么将 Ls 的每一行缩进 1-3 个空格(每行相同)的结果也构成一个具有相同内容和属性的列表项。如果一行是空的,则不需要缩进。

缩进一个空格

示例 256尝试一下
 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>

缩进两个空格

示例 257尝试一下
  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>

缩进三个空格

示例 258尝试一下
   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>

四个空格缩进产生一个代码块

示例 259尝试一下
    1.  A paragraph
        with two lines.

            indented code

        > A block quote.
<pre><code>1.  A paragraph
    with two lines.

        indented code

    &gt; A block quote.
</code></pre>
  1. 懒惰。如果一行字符串 Ls 构成了一个具有内容 Bs列表项,那么删除一行或多行中缩进后的下一个非空白字符段落延续文本的部分或全部缩进的结果,就是一个具有相同内容和属性的列表项。未缩进的行被称为懒惰延续行

这是一个带有惰性延续行的示例

示例 260尝试一下
  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>

缩进可以被部分删除

示例 261尝试一下
  1.  A paragraph
    with two lines.
<ol>
<li>A paragraph
with two lines.</li>
</ol>

这些示例显示了惰性匹配如何在嵌套结构中工作

示例 262尝试一下
> 1. > Blockquote
continued here.
<blockquote>
<ol>
<li>
<blockquote>
<p>Blockquote
continued here.</p>
</blockquote>
</li>
</ol>
</blockquote>
示例 263尝试一下
> 1. > Blockquote
> continued here.
<blockquote>
<ol>
<li>
<blockquote>
<p>Blockquote
continued here.</p>
</blockquote>
</li>
</ol>
</blockquote>
  1. 结束。 根据规则 #1–5 未被计为列表项的内容均不视为列表项

子列表的规则遵循上述通用规则。子列表必须缩进与段落包含在列表项中所需的相同空格数。

因此,在这种情况下我们需要两个空格的缩进

示例 264尝试一下
- foo
  - bar
    - baz
      - boo
<ul>
<li>foo
<ul>
<li>bar
<ul>
<li>baz
<ul>
<li>boo</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>

一个空格是不够的

示例 265尝试一下
- foo
 - bar
  - baz
   - boo
<ul>
<li>foo</li>
<li>bar</li>
<li>baz</li>
<li>boo</li>
</ul>

这里我们需要四个,因为列表标记更宽

示例 266尝试一下
10) foo
    - bar
<ol start="10">
<li>foo
<ul>
<li>bar</li>
</ul>
</li>
</ol>

三个空格是不够的

示例 267尝试一下
10) foo
   - bar
<ol start="10">
<li>foo</li>
</ol>
<ul>
<li>bar</li>
</ul>

列表可以是列表项中的第一个块

示例 268尝试一下
- - foo
<ul>
<li>
<ul>
<li>foo</li>
</ul>
</li>
</ul>
示例 269尝试一下
1. - 2. foo
<ol>
<li>
<ul>
<li>
<ol start="2">
<li>foo</li>
</ol>
</li>
</ul>
</li>
</ol>

列表项可以包含一个标题

示例 270尝试一下
- # Foo
- Bar
  ---
  baz
<ul>
<li>
<h1>Foo</h1>
</li>
<li>
<h2>Bar</h2>
baz</li>
</ul>

5.2.1动机

John Gruber 的 Markdown 规范中关于列表项的内容如下:

  1. “列表标记通常从左边距开始,但最多可以缩进三个空格。列表标记必须后跟一个或多个空格或一个制表符。”

  2. “为了让列表看起来美观,你可以用悬挂缩进包装项目……但如果你不想这样做,也没必要。”

  3. “列表项可以由多个段落组成。列表项中的每个后续段落必须缩进四个空格或一个制表符。”

  4. “缩进后续段落的每一行看起来很不错,但同样,Markdown 会允许你变得懒惰。”

  5. “要在列表项中放入引用块,引用块的 > 分隔符需要缩进。”

  6. “要在列表项中放入代码块,代码块需要缩进两次——8 个空格或两个制表符。”

这些规则指定列表项下的段落必须缩进四个空格(据推测是从左边距,而不是列表标记的开头,但这未说明),并且列表项下的代码必须缩进八个空格而不是通常的四个。它们还说引用块必须缩进,但没有说明缩进多少;然而,给出的示例有四个空格的缩进。虽然没有提到其他类型的块级内容,但推断列表项下的所有块元素(包括其他列表)都必须缩进四个空格当然是合理的。这一原则被称为四空格规则

四空格规则清晰且有原则,如果参考实现 Markdown.pl 遵循它,它可能会成为标准。然而,Markdown.pl 至少在外部层级上允许段落和子列表以仅两个空格的缩进开始。更糟糕的是,其行为不一致:外部列表的子列表需要两个空格缩进,但该子列表的子列表却需要三个空格。因此,Markdown 的不同实现为确定列表项下的内容开发了截然不同的规则并不奇怪。(例如,Pandoc 和 python-Markdown 坚持 Gruber 的语法描述和四空格规则,而 discount、redcarpet、marked、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>

四个空格的选择是任意的。它可以被学习,但不太可能被猜到,而且经常让初学者受挫。

采用双空格规则有帮助吗?问题在于,这样的规则,加上允许列表标记初始缩进 1-3 个空格的规则,允许缩进少于原始列表标记的文本包含在列表项中。例如,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 只是规定,在这种情况下,我们要求列表标记缩进一个空格(然后是缩进代码通常的四个空格)。在列表标记加上其初始缩进占用四个空格的情况下(一种常见情况),这将符合四空格规则,但在其他情况下则会分歧。

5.3列表

列表相同类型的一个或多个列表项的序列。列表项可以由任意数量的空行分隔。

如果两个列表项以相同类型的列表标记开头,则它们属于同一类型。如果 (a) 它们是使用相同字符 (-, +*) 的无序列表标记,或 (b) 它们是具有相同分隔符 (.)) 的有序列表编号,则两个列表标记属于同一类型。

如果列表由有序列表标记开头,则列表为有序列表;如果由无序列表标记开头,则为无序列表

有序列表起始编号由其初始列表项的列表编号决定。后续列表项的编号将被忽略。

如果列表的任何组成列表项由空行分隔,或者任何组成列表项直接包含两个中间有空行的块级元素,则列表为松散的。否则,列表为紧凑的。(HTML 输出的区别在于,松散列表中的段落被包裹在 <p> 标签中,而紧凑列表中的段落则不会。)

更改无序或有序列表分隔符会开始一个新的列表

示例 271尝试一下
- foo
- bar
+ baz
<ul>
<li>foo</li>
<li>bar</li>
</ul>
<ul>
<li>baz</li>
</ul>
示例 272尝试一下
1. foo
2. bar
3) baz
<ol>
<li>foo</li>
<li>bar</li>
</ol>
<ol start="3">
<li>baz</li>
</ol>

在 CommonMark 中,列表可以中断段落。也就是说,段落和随后的列表之间不需要空行

示例 273尝试一下
Foo
- bar
- baz
<p>Foo</p>
<ul>
<li>bar</li>
<li>baz</li>
</ul>

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 实践,统一原则要求我们也允许在列表项外这样做。(reStructuredText 采取了不同的方法,即使在其它列表项内也要求在列表前有空行。)

为了解决段落中出现不需要的硬换行数字列表的问题,我们只允许以 1 开头的列表中断段落。因此,

示例 274尝试一下
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>

在诸如此类的情况下,我们可能仍然会得到非预期的结果

示例 275尝试一下
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>

但该规则应该能防止大多数伪列表捕获。

项之间可以有任意数量的空行

示例 276尝试一下
- foo

- bar


- baz
<ul>
<li>
<p>foo</p>
</li>
<li>
<p>bar</p>
</li>
<li>
<p>baz</p>
</li>
</ul>
示例 277尝试一下
- 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 注释

示例 278尝试一下
- foo
- bar

<!-- -->

- baz
- bim
<ul>
<li>foo</li>
<li>bar</li>
</ul>
<!-- -->
<ul>
<li>baz</li>
<li>bim</li>
</ul>
示例 279尝试一下
-   foo

    notcode

-   foo

<!-- -->

    code
<ul>
<li>
<p>foo</p>
<p>notcode</p>
</li>
<li>
<p>foo</p>
</li>
</ul>
<!-- -->
<pre><code>code
</code></pre>

列表项不需要缩进到同一级别。以下列表项将被视为同一列表级别的项目,因为没有一个缩进足够多而属于前一个列表项

示例 280尝试一下
- 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>
示例 281尝试一下
1. a

  2. b

   3. c
<ol>
<li>
<p>a</p>
</li>
<li>
<p>b</p>
</li>
<li>
<p>c</p>
</li>
</ol>

但请注意,列表项的缩进不得超过三个空格。在此处,- e 被视为段落的延续行,因为它缩进了超过三个空格。

示例 282尝试一下
- a
 - b
  - c
   - d
    - e
<ul>
<li>a</li>
<li>b</li>
<li>c</li>
<li>d
- e</li>
</ul>

在这里,3. c 被视为缩进代码块,因为它缩进了四个空格并且前面有一个空行。

示例 283尝试一下
1. a

  2. b

    3. c
<ol>
<li>
<p>a</p>
</li>
<li>
<p>b</p>
</li>
</ol>
<pre><code>3. c
</code></pre>

这是一个松散列表,因为两个列表项之间有一个空行

示例 284尝试一下
- a
- b

- c
<ul>
<li>
<p>a</p>
</li>
<li>
<p>b</p>
</li>
<li>
<p>c</p>
</li>
</ul>

这也是,第二个项为空

示例 285尝试一下
* a
*

* c
<ul>
<li>
<p>a</p>
</li>
<li></li>
<li>
<p>c</p>
</li>
</ul>

这些是松散列表,即使项之间没有空格,因为其中一个项直接包含两个中间有空行的块级元素

示例 286尝试一下
- a
- b

  c
- d
<ul>
<li>
<p>a</p>
</li>
<li>
<p>b</p>
<p>c</p>
</li>
<li>
<p>d</p>
</li>
</ul>
示例 287尝试一下
- a
- b

  [ref]: /url
- d
<ul>
<li>
<p>a</p>
</li>
<li>
<p>b</p>
</li>
<li>
<p>d</p>
</li>
</ul>

这是一个紧凑列表,因为空行在代码块中

示例 288尝试一下
- a
- ```
  b


  ```
- c
<ul>
<li>a</li>
<li>
<pre><code>b


</code></pre>
</li>
<li>c</li>
</ul>

这是一个紧凑列表,因为空行位于子列表的两个段落之间。因此子列表是松散的,而外部列表是紧凑的

示例 289尝试一下
- a
  - b

    c
- d
<ul>
<li>a
<ul>
<li>
<p>b</p>
<p>c</p>
</li>
</ul>
</li>
<li>d</li>
</ul>

这个列表是紧凑的,因为空行在引用块内

示例 290尝试一下
* a
  > b
  >
* c
<ul>
<li>a
<blockquote>
<p>b</p>
</blockquote>
</li>
<li>c</li>
</ul>

这个列表是紧凑的,因为连续的块元素没有被空行分隔

示例 291尝试一下
- a
  > b
  ```
  c
  ```
- d
<ul>
<li>a
<blockquote>
<p>b</p>
</blockquote>
<pre><code>c
</code></pre>
</li>
<li>d</li>
</ul>

单段落列表是紧凑的

示例 292尝试一下
- a
<ul>
<li>a</li>
</ul>
示例 293尝试一下
- a
  - b
<ul>
<li>a
<ul>
<li>b</li>
</ul>
</li>
</ul>

这个列表是松散的,因为列表项中的两个块元素之间有空行

示例 294尝试一下
1. ```
   foo
   ```

   bar
<ol>
<li>
<pre><code>foo
</code></pre>
<p>bar</p>
</li>
</ol>

这里外部列表是松散的,内部列表是紧凑的

示例 295尝试一下
* foo
  * bar

  baz
<ul>
<li>
<p>foo</p>
<ul>
<li>bar</li>
</ul>
<p>baz</p>
</li>
</ul>
示例 296尝试一下
- 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>

6行内元素

行内元素是从字符流的开头到结尾(从左到右,在从左到右的语言中)依次解析的。例如:

示例 297尝试一下
`hi`lo`
<p><code>hi</code>lo`</p>

hi 被解析为代码,末尾的反引号作为字面量反引号保留。

6.1反斜杠转义

任何 ASCII 标点字符都可以使用反斜杠转义

示例 298尝试一下
\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~
<p>!&quot;#$%&amp;'()*+,-./:;&lt;=&gt;?@[\]^_`{|}~</p>

其他字符前的反斜杠被视为字面量反斜杠

示例 299尝试一下
\→\A\a\ \3\φ\«
<p>\→\A\a\ \3\φ\«</p>

转义字符被视为普通字符,不具有其通常的 Markdown 含义

示例 300尝试一下
\*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>*not emphasized*
&lt;br/&gt; not a tag
[not a link](/foo)
`not code`
1. not a list
* not a list
# not a heading
[foo]: /url &quot;not a reference&quot;
&amp;ouml; not a character entity</p>

如果反斜杠本身被转义,则随后的字符不被转义

示例 301尝试一下
\\*emphasis*
<p>\<em>emphasis</em></p>

行尾的反斜杠是 硬换行

示例 302尝试一下
foo\
bar
<p>foo<br />
bar</p>

反斜杠转义在代码块、代码片段、自动链接或原生 HTML 中不起作用

示例 303尝试一下
`` \[\` ``
<p><code>\[\`</code></p>
示例 304尝试一下
    \[\]
<pre><code>\[\]
</code></pre>
示例 305尝试一下
~~~
\[\]
~~~
<pre><code>\[\]
</code></pre>
示例 306尝试一下
<http://example.com?find=\*>
<p><a href="http://example.com?find=%5C*">http://example.com?find=\*</a></p>
示例 307尝试一下
<a href="/bar\/)">
<a href="/bar\/)">

但它们在所有其他上下文中都起作用,包括 URL 和链接标题、链接引用以及围栏代码块中的信息字符串

示例 308尝试一下
[foo](/bar\* "ti\*tle")
<p><a href="/bar*" title="ti*tle">foo</a></p>
示例 309尝试一下
[foo]

[foo]: /bar\* "ti\*tle"
<p><a href="/bar*" title="ti*tle">foo</a></p>
示例 310尝试一下
``` foo\+bar
foo
```
<pre><code class="language-foo+bar">foo
</code></pre>

6.2实体与数值字符引用

有效的 HTML 实体引用和数字字符引用可以代替相应的 Unicode 字符使用,但有以下例外:

符合标准的 CommonMark 解析器不需要存储关于特定字符在源文件中是以 Unicode 字符表示还是以实体引用表示的信息。

实体引用& + 任何有效的 HTML5 实体名称 + ; 组成。文档 https://html.whatwg.cn/multipage/entities.json 被用作有效实体引用及其对应码点的权威来源。

示例 311尝试一下
&nbsp; &amp; &copy; &AElig; &Dcaron;
&frac34; &HilbertSpace; &DifferentialD;
&ClockwiseContourIntegral; &ngE;
<p>  &amp; © Æ Ď
¾  ⅆ
∲ ≧̸</p>

十进制数值字符引用&# + 1–7 个阿拉伯数字字符串 + ; 组成。数值字符引用被解析为相应的 Unicode 字符。无效的 Unicode 码位将被替换为替换字符 (U+FFFD)。出于安全考虑,码位 U+0000 也将被替换为 U+FFFD

示例 312尝试一下
&#35; &#1234; &#992; &#0;
<p># Ӓ Ϡ �</p>

十六进制数值字符引用&# + Xx + 1-6 个十六进制数字字符串 + ; 组成。它们也被解析为相应的 Unicode 字符(此次使用十六进制数字而非十进制指定)。

示例 313尝试一下
&#X22; &#XD06; &#xcab;
<p>&quot;  ಫ</p>

这里是一些非实体引用

示例 314尝试一下
&nbsp &x; &#; &#x;
&#987654321;
&#abcdef0;
&ThisIsNotDefined; &hi?;
<p>&amp;nbsp &amp;x; &amp;#; &amp;#x;
&amp;#987654321;
&amp;#abcdef0;
&amp;ThisIsNotDefined; &amp;hi?;</p>

尽管 HTML5 确实接受某些没有末尾分号的实体引用(例如 &copy),但这里不予识别,因为这会使语法过于歧义

示例 315尝试一下
&copy
<p>&amp;copy</p>

不在 HTML5 命名实体列表中的字符串也不会被识别为实体引用

示例 316尝试一下
&MadeUpEntity;
<p>&amp;MadeUpEntity;</p>

实体和数字字符引用在除代码片段或代码块之外的任何上下文中都是可识别的,包括 URL、链接标题围栏代码块信息字符串

示例 317尝试一下
<a href="&ouml;&ouml;.html">
<a href="&ouml;&ouml;.html">
示例 318尝试一下
[foo](/f&ouml;&ouml; "f&ouml;&ouml;")
<p><a href="/f%C3%B6%C3%B6" title="föö">foo</a></p>
示例 319尝试一下
[foo]

[foo]: /f&ouml;&ouml; "f&ouml;&ouml;"
<p><a href="/f%C3%B6%C3%B6" title="föö">foo</a></p>
示例 320尝试一下
``` f&ouml;&ouml;
foo
```
<pre><code class="language-föö">foo
</code></pre>

在代码片段和代码块中,实体和数字字符引用被视为字面文本。

示例 321尝试一下
`f&ouml;&ouml;`
<p><code>f&amp;ouml;&amp;ouml;</code></p>
示例 322尝试一下
    f&ouml;f&ouml;
<pre><code>f&amp;ouml;f&amp;ouml;
</code></pre>

实体和数字字符引用不能在 CommonMark 文档中代替表示结构的符号使用。

示例 323尝试一下
&#42;foo&#42;
*foo*
<p>*foo*
<em>foo</em></p>
示例 324尝试一下
&#42; foo

* foo
<p>* foo</p>
<ul>
<li>foo</li>
</ul>
示例 325尝试一下
foo&#10;&#10;bar
<p>foo

bar</p>
示例 326尝试一下
&#9;foo
<p>→foo</p>
示例 327尝试一下
[a](url &quot;tit&quot;)
<p>[a](url &quot;tit&quot;)</p>

6.3代码片段

反引号字符串是指一串包含一个或多个反引号字符(`)的字符串,且其前后均无反引号。

代码跨度以反引号字符串开始,并以等长的反引号字符串结束。代码跨度的内容是两个反引号字符串之间的字符,并按以下方式规范化。

这是一个简单的代码跨度

示例 328尝试一下
`foo`
<p><code>foo</code></p>

这里使用了两个反引号,因为代码包含一个反引号。此示例还说明了单个前导和尾随空格的剥离

示例 329尝试一下
`` foo ` bar ``
<p><code>foo ` bar</code></p>

此示例展示了去除前导和尾随空格的原因。

示例 330尝试一下
` `` `
<p><code>``</code></p>

注意,只剥离一个空格

示例 331尝试一下
`  ``  `
<p><code> `` </code></p>

仅当字符串两侧都有空格时才会发生剥离

示例 332尝试一下
` a`
<p><code> a</code></p>

只有空格,而非一般的Unicode 空白,会以这种方式剥离

示例 333尝试一下
` b `
<p><code> b </code></p>

如果代码片段仅包含空格,则不会发生剥离

示例 334尝试一下
` `
`  `
<p><code> </code>
<code>  </code></p>

行尾符被视为类似空格的处理。

示例 335尝试一下
``
foo
bar  
baz
``
<p><code>foo bar   baz</code></p>
示例 336尝试一下
``
foo 
``
<p><code>foo </code></p>

内部空格不会折叠

示例 337尝试一下
`foo   bar 
baz`
<p><code>foo   bar  baz</code></p>

注意,浏览器在渲染 <code> 元素时通常会折叠连续的空格,因此建议使用以下 CSS

code{white-space: pre-wrap;}

请注意,反斜杠转义在代码跨度中不起作用。所有反斜杠均被视为字面字符。

示例 338尝试一下
`foo\`bar`
<p><code>foo\</code>bar`</p>

反斜杠转义永远是不需要的,因为人们总是可以选择包含 n 个反引号字符的字符串作为定界符,而代码本身不包含任何恰好为 n 个反引号的字符串。

示例 339尝试一下
``foo`bar``
<p><code>foo`bar</code></p>
示例 340尝试一下
` foo `` bar `
<p><code>foo `` bar</code></p>

代码跨度的反引号优先级高于除了 HTML 标签和自动链接之外的任何行内结构。因此,例如,这不会被解析为强调文本,因为第二个 * 是代码跨度的一部分。

示例 341尝试一下
*foo`*`
<p>*foo<code>*</code></p>

且这也不会被解析为链接。

示例 342尝试一下
[not a `link](/foo`)
<p>[not a <code>link](/foo</code>)</p>

代码跨度、HTML 标签和自动链接具有相同的优先级。因此,这是代码。

示例 343尝试一下
`<a href="`">`
<p><code>&lt;a href=&quot;</code>&quot;&gt;`</p>

但这却是一个 HTML 标签。

示例 344尝试一下
<a href="`">`
<p><a href="`">`</p>

而这则是代码。

示例 345尝试一下
`<http://foo.bar.`baz>`
<p><code>&lt;http://foo.bar.</code>baz&gt;`</p>

但这又是一个自动链接。

示例 346尝试一下
<http://foo.bar.`baz>`
<p><a href="http://foo.bar.%60baz">http://foo.bar.`baz</a>`</p>

当反引号字符串没有匹配的反引号字符串闭合时,我们得到的只是字面意义上的反引号。

示例 347尝试一下
```foo``
<p>```foo``</p>
示例 348尝试一下
`foo
<p>`foo</p>

以下情况也说明了起始和闭合反引号字符串长度必须相等的必要性

示例 349尝试一下
`foo``bar``
<p>`foo<code>bar</code></p>

6.4强调与加粗

John Gruber 原版的 Markdown 语法描述 说道:

Markdown 将星号(*)和下划线(_)视为强调的指示符。被单个 *_ 包围的文本将被 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) 其后不跟标点字符,或 (2b) 其后跟标点字符且其前是 Unicode 空白字符标点字符。在本定义的用途中,行首和行尾均视为 Unicode 空白字符。

右侧侧翼定界符序列是指满足以下条件的定界符序列:(1) 其前不跟 Unicode 空白字符,且 (2a) 其前不跟标点字符,或 (2b) 其前跟标点字符且其后是 Unicode 空白字符标点字符。在本定义的用途中,行首和行尾均视为 Unicode 空白字符。

以下是一些定界符序列的示例。

(根据前后的字符来区分左侧侧翼和右侧侧翼定界符序列的想法来源于 Roopesh Chander 的 vfmd。vfmd 使用“强调指示符字符串”而不是“定界符序列”这一术语,其区分左右侧翼序列的规则比这里给出的要复杂一些。)

以下规则定义了强调和强强调。

  1. 单个 * 字符 可以开启强调,当且仅当它是 左侧侧翼定界符序列 的一部分。

  2. 单个 _ 字符 可以开启强调,当且仅当它是 左侧侧翼定界符序列 的一部分,且满足 (a) 不是 右侧侧翼定界符序列 的一部分,或者 (b) 是前接标点的 右侧侧翼定界符序列 的一部分。

  3. 单个 * 字符 可以关闭强调,当且仅当它是 右侧侧翼定界符序列 的一部分。

  4. 单个 _ 字符 可以关闭强调,当且仅当它是 右侧侧翼定界符序列 的一部分,且满足 (a) 不是 左侧侧翼定界符序列 的一部分,或者 (b) 是后接标点的 左侧侧翼定界符序列 的一部分。

  5. ** 可以开启强强调,当且仅当它是 左侧侧翼定界符序列 的一部分。

  6. __ 可以开启强强调,当且仅当它是 左侧侧翼定界符序列 的一部分,且满足 (a) 不是 右侧侧翼定界符序列 的一部分,或者 (b) 是前接标点的 右侧侧翼定界符序列 的一部分。

  7. ** 可以关闭强强调,当且仅当它是 右侧侧翼定界符序列 的一部分。

  8. 双重 __ 可以关闭强强调,当且仅当它是右侧侧翼定界符序列的一部分,且要么 (a) 不是左侧侧翼定界符序列的一部分,要么 (b) 是左侧侧翼定界符序列的一部分且其后紧跟标点符号。

  9. 强调以一个可以开启强调的分隔符开始,并以一个可以关闭强调的分隔符结束,并且使用与起始分隔符相同的字符 (_*)。起始和闭合分隔符必须属于独立的分隔符序列。如果其中一个分隔符既可以开启也可以关闭强调,那么包含起始和闭合分隔符的分隔符序列长度之和必须不是 3 的倍数,除非两个长度都是 3 的倍数。

  10. 加重强调以一个可以开启加重强调的分隔符开始,并以一个可以关闭加重强调的分隔符结束,并且使用与起始分隔符相同的字符 (_*)。起始和闭合分隔符必须属于独立的分隔符序列。如果其中一个分隔符既可以开启也可以关闭加重强调,那么包含起始和闭合分隔符的分隔符序列长度之和必须不是 3 的倍数,除非两个长度都是 3 的倍数。

  11. 除非经过反斜杠转义,否则字面意义上的 * 字符不能出现在 * 定界的强调或 ** 定界的强强调的开头或结尾。

  12. 除非经过反斜杠转义,否则字面意义上的 _ 字符不能出现在 _ 定界的强调或 __ 定界的强强调的开头或结尾。

在上述 1–12 条规则与多种解析结果兼容的情况下,以下原则用于解决歧义。

  1. 应尽可能减少嵌套数量。因此,例如,解释为 <strong>...</strong> 总是优先于 <em><em>...</em></em>

  2. <em><strong>...</strong></em> 的解释总是优于 <strong><em>...</em></strong>

  3. 当两个潜在的强调或加重强调跨度重叠时,即第二个在第一个结束之前开始并在第一个结束之后结束,第一个优先。例如,*foo _bar* baz_ 被解析为 <em>foo _bar</em> baz_,而不是 *foo <em>bar* baz</em>

  4. 当有两个具有相同关闭定界符的潜在强调或强强调跨度时,较短的一个(后开启的那个)优先。因此,例如,**foo **bar baz** 被解析为 **foo <strong>bar baz</strong> 而不是 <strong>foo **bar baz</strong>

  5. 行内代码跨度、链接、图像和 HTML 标签的结合比强调更紧密。因此,当在包含这些元素与不包含这些元素的解释之间进行选择时,前者总是胜出。因此,例如,*[foo*](bar) 被解析为 *<a href="bar">foo*</a> 而不是 <em>[foo</em>](bar)

这些规则可以通过一系列示例来说明。

规则 1

示例 350尝试一下
*foo bar*
<p><em>foo bar</em></p>

这不是强调,因为开启的 * 后跟有空格,因此不是 左侧侧翼定界符序列 的一部分。

示例 351尝试一下
a * foo bar*
<p>a * foo bar*</p>

这不是强调,因为开启的 * 前是字母数字,后是标点符号,因此不是 左侧侧翼定界符序列 的一部分。

示例 352尝试一下
a*"foo"*
<p>a*&quot;foo&quot;*</p>

Unicode 不换行空格也计为空白字符。

示例 353尝试一下
* a *
<p>* a *</p>

允许使用 * 进行词内强调。

示例 354尝试一下
foo*bar*
<p>foo<em>bar</em></p>
示例 355尝试一下
5*6*78
<p>5<em>6</em>78</p>

规则 2

示例 356尝试一下
_foo bar_
<p><em>foo bar</em></p>

这不是强调,因为开启的 _ 后跟有空格。

示例 357尝试一下
_ foo bar_
<p>_ foo bar_</p>

这不是强调,因为开启的 _ 前是字母数字,后是标点符号。

示例 358尝试一下
a_"foo"_
<p>a_&quot;foo&quot;_</p>

不允许在单词内部使用 _ 进行强调。

示例 359尝试一下
foo_bar_
<p>foo_bar_</p>
示例 360尝试一下
5_6_78
<p>5_6_78</p>
示例 361尝试一下
пристаням_стремятся_
<p>пристаням_стремятся_</p>

此处 _ 不产生强调,因为第一个定界符序列是右侧侧翼,而第二个是左侧侧翼。

示例 362尝试一下
aa_"bb"_cc
<p>aa_&quot;bb&quot;_cc</p>

这是强调,即使开启定界符既是左侧侧翼也是右侧侧翼,因为它前接标点。

示例 363尝试一下
foo-_(bar)_
<p>foo-<em>(bar)</em></p>

规则 3

这不是强调,因为关闭定界符与开启定界符不匹配。

示例 364尝试一下
_foo*
<p>_foo*</p>

这不是强调,因为关闭的 * 前面有空格。

示例 365尝试一下
*foo bar *
<p>*foo bar *</p>

换行符也被计为空白字符。

示例 366尝试一下
*foo bar
*
<p>*foo bar
*</p>

这不是强调,因为第二个 * 前面是标点符号,后面是字母数字(因此它不是 右侧侧翼定界符序列 的一部分)。

示例 367尝试一下
*(*foo)
<p>*(*foo)</p>

此限制的意义可以通过以下示例更清楚地理解。

示例 368尝试一下
*(*foo*)*
<p><em>(<em>foo</em>)</em></p>

允许使用 * 进行词内强调。

示例 369尝试一下
*foo*bar
<p><em>foo</em>bar</p>

规则 4

这不是强调,因为关闭的 _ 前面有空格。

示例 370尝试一下
_foo bar _
<p>_foo bar _</p>

这不是强调,因为第二个 _ 前面是标点符号,后面是字母数字。

示例 371尝试一下
_(_foo)
<p>_(_foo)</p>

这是强调嵌套在强调中。

示例 372尝试一下
_(_foo_)_
<p><em>(<em>foo</em>)</em></p>

对于 _ 不允许进行词内强调。

示例 373尝试一下
_foo_bar
<p>_foo_bar</p>
示例 374尝试一下
_пристаням_стремятся
<p>_пристаням_стремятся</p>
示例 375尝试一下
_foo_bar_baz_
<p><em>foo_bar_baz</em></p>

这是强调,即使关闭定界符既是左侧侧翼也是右侧侧翼,因为它后接标点。

示例 376尝试一下
_(bar)_.
<p><em>(bar)</em>.</p>

规则 5

示例 377尝试一下
**foo bar**
<p><strong>foo bar</strong></p>

这不是强强调,因为开启定界符后跟有空格。

示例 378尝试一下
** foo bar**
<p>** foo bar**</p>

这不是强强调,因为开启的 ** 前是字母数字,后是标点符号,因此不是 左侧侧翼定界符序列 的一部分。

示例 379尝试一下
a**"foo"**
<p>a**&quot;foo&quot;**</p>

允许使用 ** 进行词内强强调。

示例 380尝试一下
foo**bar**
<p>foo<strong>bar</strong></p>

规则 6

示例 381尝试一下
__foo bar__
<p><strong>foo bar</strong></p>

这不是强强调,因为开启定界符后跟有空格。

示例 382尝试一下
__ foo bar__
<p>__ foo bar__</p>

换行符计为空白字符。

示例 383尝试一下
__
foo bar__
<p>__
foo bar__</p>

这不是强强调,因为开启的 __ 前是字母数字,后是标点符号。

示例 384尝试一下
a__"foo"__
<p>a__&quot;foo&quot;__</p>

禁止使用 __ 进行词内强强调。

示例 385尝试一下
foo__bar__
<p>foo__bar__</p>
示例 386尝试一下
5__6__78
<p>5__6__78</p>
示例 387尝试一下
пристаням__стремятся__
<p>пристаням__стремятся__</p>
示例 388尝试一下
__foo, __bar__, baz__
<p><strong>foo, <strong>bar</strong>, baz</strong></p>

这是强强调,即使开启定界符既是左侧侧翼也是右侧侧翼,因为它前接标点。

示例 389尝试一下
foo-__(bar)__
<p>foo-<strong>(bar)</strong></p>

规则 7

这不是强强调,因为关闭定界符前面有空格。

示例 390尝试一下
**foo bar **
<p>**foo bar **</p>

(根据规则 11,它也不能被解释为强调的 *foo bar *。)

这不是强强调,因为第二个 ** 前是标点符号,后是字母数字。

示例 391试一试
**(**foo)
<p>**(**foo)</p>

此限制的意义可以通过这些示例更清楚地理解。

示例 392试一试
*(**foo**)*
<p><em>(<strong>foo</strong>)</em></p>
示例 393试一试
**Gomphocarpus (*Gomphocarpus physocarpus*, syn.
*Asclepias physocarpa*)**
<p><strong>Gomphocarpus (<em>Gomphocarpus physocarpus</em>, syn.
<em>Asclepias physocarpa</em>)</strong></p>
示例 394试一试
**foo "*bar*" foo**
<p><strong>foo &quot;<em>bar</em>&quot; foo</strong></p>

词内强调

示例 395试一试
**foo**bar
<p><strong>foo</strong>bar</p>

规则 8

这不是强强调,因为关闭定界符前面有空格。

示例 396试一试
__foo bar __
<p>__foo bar __</p>

这不是强强调,因为第二个 __ 前是标点符号,后是字母数字。

示例 397试一试
__(__foo)
<p>__(__foo)</p>

此限制的意义可以通过以下示例更清楚地理解。

示例 398试一试
_(__foo__)_
<p><em>(<strong>foo</strong>)</em></p>

禁止使用 __ 进行词内强强调。

示例 399试一试
__foo__bar
<p>__foo__bar</p>
示例 400试一试
__пристаням__стремятся
<p>__пристаням__стремятся</p>
示例 401试一试
__foo__bar__baz__
<p><strong>foo__bar__baz</strong></p>

这是强强调,即使关闭定界符既是左侧侧翼也是右侧侧翼,因为它后接标点。

示例 402试一试
__(bar)__.
<p><strong>(bar)</strong>.</p>

规则 9

任何非空的行内元素序列都可以作为强调跨度的内容。

示例 403试一试
*foo [bar](/url)*
<p><em>foo <a href="/url">bar</a></em></p>
示例 404试一试
*foo
bar*
<p><em>foo
bar</em></p>

特别是,强调和强强调可以嵌套在强调内。

示例 405试一试
_foo __bar__ baz_
<p><em>foo <strong>bar</strong> baz</em></p>
示例 406试一试
_foo _bar_ baz_
<p><em>foo <em>bar</em> baz</em></p>
示例 407试一试
__foo_ bar_
<p><em><em>foo</em> bar</em></p>
示例 408试一试
*foo *bar**
<p><em>foo <em>bar</em></em></p>
示例 409试一试
*foo **bar** baz*
<p><em>foo <strong>bar</strong> baz</em></p>
示例 410试一试
*foo**bar**baz*
<p><em>foo<strong>bar</strong>baz</em></p>

注意,在上述情况中,这种解释被以下条件所排除:如果一个既能作为开头又能作为结尾的分隔符(例如 foo 后面的 *)所在的分隔符序列总长度是 3 的倍数,那么除非其两个部分的长度都是 3 的倍数,否则它不能形成强调。

<p><em>foo</em><em>bar<em></em>baz</em></p>

出于同样的原因,在此示例中我们不会得到两个连续的强调部分

在此示例中,我们得不到两个连续的强调部分

示例 411试一试
*foo**bar*
<p><em>foo**bar</em></p>

相同的条件确保了即使在省略内部空格时,以下情况也都是嵌套在强调内的强强调:

示例 412试一试
***foo** bar*
<p><em><strong>foo</strong> bar</em></p>
示例 413试一试
*foo **bar***
<p><em>foo <strong>bar</strong></em></p>
示例 414试一试
*foo**bar***
<p><em>foo<strong>bar</strong></em></p>

然而,当内部结束分隔符序列和起始分隔符序列的长度是 3 的倍数时,它们可以匹配以形成强调

示例 415试一试
foo***bar***baz
<p>foo<em><strong>bar</strong></em>baz</p>
示例 416试一试
foo******bar*********baz
<p>foo<strong><strong><strong>bar</strong></strong></strong>***baz</p>

支持无限级的嵌套。

示例 417试一试
*foo **bar *baz* bim** bop*
<p><em>foo <strong>bar <em>baz</em> bim</strong> bop</em></p>
示例 418试一试
*foo [*bar*](/url)*
<p><em>foo <a href="/url"><em>bar</em></a></em></p>

不存在空强调或空强强调。

示例 419试一试
** is not an empty emphasis
<p>** is not an empty emphasis</p>
示例 420试一试
**** is not an empty strong emphasis
<p>**** is not an empty strong emphasis</p>

规则 10

任何非空的行内元素序列都可以作为强强调跨度的内容。

示例 421试一试
**foo [bar](/url)**
<p><strong>foo <a href="/url">bar</a></strong></p>
示例 422试一试
**foo
bar**
<p><strong>foo
bar</strong></p>

特别是,强调和强强调可以嵌套在强强调内。

示例 423试一试
__foo _bar_ baz__
<p><strong>foo <em>bar</em> baz</strong></p>
示例 424试一试
__foo __bar__ baz__
<p><strong>foo <strong>bar</strong> baz</strong></p>
示例 425试一试
____foo__ bar__
<p><strong><strong>foo</strong> bar</strong></p>
示例 426试一试
**foo **bar****
<p><strong>foo <strong>bar</strong></strong></p>
示例 427试一试
**foo *bar* baz**
<p><strong>foo <em>bar</em> baz</strong></p>
示例 428试一试
**foo*bar*baz**
<p><strong>foo<em>bar</em>baz</strong></p>
示例 429试一试
***foo* bar**
<p><strong><em>foo</em> bar</strong></p>
示例 430试一试
**foo *bar***
<p><strong>foo <em>bar</em></strong></p>

支持无限级的嵌套。

示例 431试一试
**foo *bar **baz**
bim* bop**
<p><strong>foo <em>bar <strong>baz</strong>
bim</em> bop</strong></p>
示例 432试一试
**foo [*bar*](/url)**
<p><strong>foo <a href="/url"><em>bar</em></a></strong></p>

不存在空强调或空强强调。

示例 433试一试
__ is not an empty emphasis
<p>__ is not an empty emphasis</p>
示例 434试一试
____ is not an empty strong emphasis
<p>____ is not an empty strong emphasis</p>

规则 11

示例 435试一试
foo ***
<p>foo ***</p>
示例 436试一试
foo *\**
<p>foo <em>*</em></p>
示例 437试一试
foo *_*
<p>foo <em>_</em></p>
示例 438试一试
foo *****
<p>foo *****</p>
示例 439试一试
foo **\***
<p>foo <strong>*</strong></p>
示例 440试一试
foo **_**
<p>foo <strong>_</strong></p>

请注意,当定界符不均匀匹配时,规则 11 确定多余的字面 * 字符将出现在强调之外,而不是之内。

示例 441试一试
**foo*
<p>*<em>foo</em></p>
示例 442试一试
*foo**
<p><em>foo</em>*</p>
示例 443试一试
***foo**
<p>*<strong>foo</strong></p>
示例 444试一试
****foo*
<p>***<em>foo</em></p>
示例 445试一试
**foo***
<p><strong>foo</strong>*</p>
示例 446试一试
*foo****
<p><em>foo</em>***</p>

规则 12

示例 447试一试
foo ___
<p>foo ___</p>
示例 448试一试
foo _\__
<p>foo <em>_</em></p>
示例 449试一试
foo _*_
<p>foo <em>*</em></p>
示例 450试一试
foo _____
<p>foo _____</p>
示例 451试一试
foo __\___
<p>foo <strong>_</strong></p>
示例 452试一试
foo __*__
<p>foo <strong>*</strong></p>
示例 453试一试
__foo_
<p>_<em>foo</em></p>

请注意,当定界符不均匀匹配时,规则 12 确定多余的字面 _ 字符将出现在强调之外,而不是之内。

示例 454试一试
_foo__
<p><em>foo</em>_</p>
示例 455试一试
___foo__
<p>_<strong>foo</strong></p>
示例 456试一试
____foo_
<p>___<em>foo</em></p>
示例 457试一试
__foo___
<p><strong>foo</strong>_</p>
示例 458试一试
_foo____
<p><em>foo</em>___</p>

规则 13 意味着,如果您希望强调直接嵌套在强调内,则必须使用不同的定界符。

示例 459试一试
**foo**
<p><strong>foo</strong></p>
示例 460试一试
*_foo_*
<p><em><em>foo</em></em></p>
示例 461试一试
__foo__
<p><strong>foo</strong></p>
示例 462试一试
_*foo*_
<p><em><em>foo</em></em></p>

然而,在不切换定界符的情况下,强强调嵌套在强强调内是可能的。

示例 463试一试
****foo****
<p><strong><strong>foo</strong></strong></p>
示例 464试一试
____foo____
<p><strong><strong>foo</strong></strong></p>

规则 13 可应用于任意长度的定界符序列。

示例 465试一试
******foo******
<p><strong><strong><strong>foo</strong></strong></strong></p>

规则 14

示例 466试一试
***foo***
<p><em><strong>foo</strong></em></p>
示例 467试一试
_____foo_____
<p><em><strong><strong>foo</strong></strong></em></p>

规则 15

示例 468试一试
*foo _bar* baz_
<p><em>foo _bar</em> baz_</p>
示例 469试一试
*foo __bar *baz bim__ bam*
<p><em>foo <strong>bar *baz bim</strong> bam</em></p>

规则 16

示例 470试一试
**foo **bar baz**
<p>**foo <strong>bar baz</strong></p>
示例 471试一试
*foo *bar baz*
<p>*foo <em>bar baz</em></p>

规则 17

示例 472试一试
*[bar*](/url)
<p>*<a href="/url">bar*</a></p>
示例 473试一试
_foo [bar_](/url)
<p>_foo <a href="/url">bar_</a></p>
示例 474试一试
*<img src="foo" title="*"/>
<p>*<img src="foo" title="*"/></p>
示例 475试一试
**<a href="**">
<p>**<a href="**"></p>
示例 476试一试
__<a href="__">
<p>__<a href="__"></p>
示例 477试一试
*a `*`*
<p><em>a <code>*</code></em></p>
示例 478试一试
_a `_`_
<p><em>a <code>_</code></em></p>
示例 479试一试
**a<http://foo.bar/?q=**>
<p>**a<a href="http://foo.bar/?q=**">http://foo.bar/?q=**</a></p>
示例 480试一试
__a<http://foo.bar/?q=__>
<p>__a<a href="http://foo.bar/?q=__">http://foo.bar/?q=__</a></p>

链接包含 链接文本(可见文本)、链接目标(作为链接目标的 URI)以及可选的 链接标题。Markdown 中有两种基本链接。在 行内链接 中,目标和标题紧跟在链接文本之后。在 引用链接 中,目标和标题定义在文档的其他地方。

链接文本由方括号([])括起来的零个或多个行内元素序列组成。适用以下规则:

链接目标由以下两者之一组成:

链接标题由以下两者之一组成:

尽管 链接标题 可以跨越多行,但它们不得包含 空行

行内链接链接文本 紧随左圆括号 (、可选的 空白字符、可选的 链接目标、通过 空白字符 与链接目标分隔的可选 链接标题、可选的 空白字符 以及右圆括号 ) 组成。链接文本包含 链接文本 中包含的行内元素(不包括包围的方括号)。链接 URI 包含链接目标,若存在则不包括包围的 <...>,并按上述规定应用反斜杠转义。链接标题包含链接标题,不包括其包围的定界符,并按上述规定应用反斜杠转义。

这是一个简单的行内链接:

示例 481试一试
[link](/uri "title")
<p><a href="/uri" title="title">link</a></p>

标题可以省略

示例 482试一试
[link](/uri)
<p><a href="/uri">link</a></p>

标题和目标均可省略。

示例 483试一试
[link]()
<p><a href="">link</a></p>
示例 484试一试
[link](<>)
<p><a href="">link</a></p>

目标仅在用尖括号括起来时才能包含空格

示例 485试一试
[link](/my uri)
<p>[link](/my uri)</p>
示例 486试一试
[link](</my uri>)
<p><a href="/my%20uri">link</a></p>

即使包含在尖括号中,目标也不能包含换行符。

示例 487试一试
[link](foo
bar)
<p>[link](foo
bar)</p>
示例 488试一试
[link](<foo
bar>)
<p>[link](<foo
bar>)</p>

如果用尖括号括起来,目标可以包含 )

示例 489试一试
[a](<b)c>)
<p><a href="b)c">a</a></p>

括起链接的尖括号必须是非转义的

示例 490试一试
[link](<foo\>)
<p>[link](&lt;foo&gt;)</p>

这些不是链接,因为起始尖括号没有正确匹配

示例 491试一试
[a](<b)c
[a](<b)c>
[a](<b>c)
<p>[a](&lt;b)c
[a](&lt;b)c&gt;
[a](<b>c)</p>

链接目标内的圆括号可以进行转义

示例 492试一试
[link](\(foo\))
<p><a href="(foo)">link</a></p>

只要圆括号是平衡的,任意数量的圆括号都可以在无需转义的情况下使用

示例 493试一试
[link](foo(and(bar)))
<p><a href="foo(and(bar))">link</a></p>

但是,如果你有不平衡的圆括号,你需要对其进行转义或使用 <...> 形式

示例 494试一试
[link](foo\(and\(bar\))
<p><a href="foo(and(bar)">link</a></p>
示例 495试一试
[link](<foo(and(bar)>)
<p><a href="foo(and(bar)">link</a></p>

圆括号和其他符号也可以按照 Markdown 中的惯例进行转义。

示例 496试一试
[link](foo\)\:)
<p><a href="foo):">link</a></p>

链接可以包含片段标识符和查询字符串。

示例 497试一试
[link](#fragment)

[link](http://example.com#fragment)

[link](http://example.com?foo=3#frag)
<p><a href="#fragment">link</a></p>
<p><a href="http://example.com#fragment">link</a></p>
<p><a href="http://example.com?foo=3#frag">link</a></p>

请注意,不可转义字符前的反斜杠仅被视为反斜杠。

示例 498试一试
[link](foo\bar)
<p><a href="foo%5Cbar">link</a></p>

URL 转义在目标内部应保持原样,因为所有 URL 转义字符也是有效的 URL 字符。目标中的实体和数值字符引用将按惯例解析为相应的 Unicode 码位。当写入 HTML 时,这些字符可以选配地进行 URL 转义,但本规范不对在 HTML 或其他格式中渲染 URL 的特定策略进行强制。渲染器可能对如何在输出中转义或规范化 URL 做出不同的决定。

示例 499试一试
[link](foo%20b&auml;)
<p><a href="foo%20b%C3%A4">link</a></p>

请注意,由于标题通常可以被解析为目标,如果您尝试省略目标并保留标题,则会得到意外结果。

示例 500试一试
[link]("title")
<p><a href="%22title%22">link</a></p>

标题可以使用单引号、双引号或圆括号。

示例 501试一试
[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>

标题中可以使用反斜杠转义以及实体和数值字符引用。

示例 502试一试
[link](/url "title \"&quot;")
<p><a href="/url" title="title &quot;&quot;">link</a></p>

标题必须使用空白与链接分隔。其它 Unicode 空白(如不换行空格)不起作用。

示例 503试一试
[link](/url "title")
<p><a href="/url%C2%A0%22title%22">link</a></p>

除非经过转义,否则不允许嵌套平衡的引号。

示例 504试一试
[link](/url "title "and" title")
<p>[link](/url &quot;title &quot;and&quot; title&quot;)</p>

但可以通过使用不同的引号类型轻松解决此问题。

示例 505试一试
[link](/url 'title "and" title')
<p><a href="/url" title="title &quot;and&quot; title">link</a></p>

(注意:Markdown.pl 确实允许在双引号标题中使用双引号,并且其测试套件包含一个证明此点的测试。但很难看出其带来的额外复杂性的充分理由,因为已经有许多方法——反斜杠转义、实体和数值字符引用,或者为外层标题使用不同的引号类型——来编写包含双引号的标题。Markdown.pl 对标题的处理还有许多其他奇怪的特性。例如,它在行内链接中允许单引号标题,但在引用链接中则不允许。此外,在引用链接而非行内链接中,它允许标题以 " 开头并以 ) 结尾。Markdown.pl 1.0.1 甚至允许没有闭合引号的标题,尽管 1.0.2b8 不允许。采用一种简单、合理的规则,使行内链接和链接引用定义的工作方式相同,似乎更为可取。)

目标和标题周围允许使用 空白字符

示例 506试一试
[link](   /uri
  "title"  )
<p><a href="/uri" title="title">link</a></p>

但链接文本和随后的圆括号之间不允许使用。

示例 507试一试
[link] (/uri)
<p>[link] (/uri)</p>

链接文本可以包含平衡的括号,但不能包含不平衡的括号,除非它们经过转义。

示例 508试一试
[link [foo [bar]]](/uri)
<p><a href="/uri">link [foo [bar]]</a></p>
示例 509试一试
[link] bar](/uri)
<p>[link] bar](/uri)</p>
示例 510试一试
[link [bar](/uri)
<p>[link <a href="/uri">bar</a></p>
示例 511试一试
[link \[bar](/uri)
<p><a href="/uri">link [bar</a></p>

链接文本可以包含行内内容。

示例 512试一试
[link *foo **bar** `#`*](/uri)
<p><a href="/uri">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>
示例 513试一试
[![moon](moon.jpg)](/uri)
<p><a href="/uri"><img src="moon.jpg" alt="moon" /></a></p>

但是,链接不得包含其他链接,无论嵌套层级如何。

示例 514试一试
[foo [bar](/uri)](/uri)
<p>[foo <a href="/uri">bar</a>](/uri)</p>
示例 515试一试
[foo *[bar [baz](/uri)](/uri)*](/uri)
<p>[foo <em>[bar <a href="/uri">baz</a>](/uri)</em>](/uri)</p>
示例 516试一试
![[[foo](uri1)](uri2)](uri3)
<p><img src="uri3" alt="[foo](uri2)" /></p>

这些情况说明了链接文本分组优于强调分组的优先级。

示例 517试一试
*[foo*](/uri)
<p>*<a href="/uri">foo*</a></p>
示例 518试一试
[foo *bar](baz*)
<p><a href="baz*">foo *bar</a></p>

请注意,属于链接的方括号没有优先级。

示例 519试一试
*foo [bar* baz]
<p><em>foo [bar</em> baz]</p>

这些情况说明了 HTML 标签、代码跨度和自动链接优于链接分组的优先级。

示例 520试一试
[foo <bar attr="](baz)">
<p>[foo <bar attr="](baz)"></p>
示例 521试一试
[foo`](/uri)`
<p>[foo<code>](/uri)</code></p>
示例 522试一试
[foo<http://example.com/?search=](uri)>
<p>[foo<a href="http://example.com/?search=%5D(uri)">http://example.com/?search=](uri)</a></p>

有三种类型的 引用链接完整型折叠型快捷型

完整引用链接链接文本 紧随一个 链接标签 组成,该标签 匹配 文档其他位置的 链接引用定义

链接标签以左括号 ([) 开始,以第一个未被反斜杠转义的右括号 (]) 结束。在这些括号之间必须至少有一个非空白字符。未转义的方括号字符不允许出现在链接标签的开闭方括号内。链接标签在方括号内最多可有 999 个字符。

当且仅当一个标签的规范化形式相等时,该标签才匹配另一个。要规范化标签,请去掉开闭方括号,执行 Unicode 大小写折叠,去除前导和尾随的空白字符,并将连续的内部空白字符折叠为单个空格。如果有多个匹配的引用链接定义,则使用文档中首先出现的那个。(在这种情况下最好发出警告。)

第一个链接标签的内容被解析为行内元素,用作链接的文本。链接的 URI 和标题由匹配的 链接引用定义 提供。

这是一个简单的例子

示例 523试一试
[foo][bar]

[bar]: /url "title"
<p><a href="/url" title="title">foo</a></p>

链接文本 的规则与 行内链接 的规则相同。因此:

链接文本可以包含平衡的括号,但不能包含不平衡的括号,除非它们经过转义。

示例 524试一试
[link [foo [bar]]][ref]

[ref]: /uri
<p><a href="/uri">link [foo [bar]]</a></p>
示例 525试一试
[link \[bar][ref]

[ref]: /uri
<p><a href="/uri">link [bar</a></p>

链接文本可以包含行内内容。

示例 526试一试
[link *foo **bar** `#`*][ref]

[ref]: /uri
<p><a href="/uri">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>
示例 527试一试
[![moon](moon.jpg)][ref]

[ref]: /uri
<p><a href="/uri"><img src="moon.jpg" alt="moon" /></a></p>

但是,链接不得包含其他链接,无论嵌套层级如何。

示例 528试一试
[foo [bar](/uri)][ref]

[ref]: /uri
<p>[foo <a href="/uri">bar</a>]<a href="/uri">ref</a></p>
示例 529试一试
[foo *bar [baz][ref]*][ref]

[ref]: /uri
<p>[foo <em>bar <a href="/uri">baz</a></em>]<a href="/uri">ref</a></p>

(在上述示例中,我们有两个 快捷引用链接,而不是一个 完整引用链接。)

以下情况说明了链接文本分组优于强调分组的优先级。

示例 530试一试
*[foo*][ref]

[ref]: /uri
<p>*<a href="/uri">foo*</a></p>
示例 531试一试
[foo *bar][ref]

[ref]: /uri
<p><a href="/uri">foo *bar</a></p>

这些情况说明了 HTML 标签、代码跨度和自动链接优于链接分组的优先级。

示例 532试一试
[foo <bar attr="][ref]">

[ref]: /uri
<p>[foo <bar attr="][ref]"></p>
示例 533试一试
[foo`][ref]`

[ref]: /uri
<p>[foo<code>][ref]</code></p>
示例 534试一试
[foo<http://example.com/?search=][ref]>

[ref]: /uri
<p>[foo<a href="http://example.com/?search=%5D%5Bref%5D">http://example.com/?search=][ref]</a></p>

匹配时大小写不敏感。

示例 535试一试
[foo][BaR]

[bar]: /url "title"
<p><a href="/url" title="title">foo</a></p>

使用 Unicode 大小写折叠。

示例 536试一试
[Толпой][Толпой] is a Russian word.

[ТОЛПОЙ]: /url
<p><a href="/url">Толпой</a> is a Russian word.</p>

在确定匹配时,连续的内部 空白字符 被视为一个空格。

示例 537试一试
[Foo
  bar]: /url

[Baz][Foo bar]
<p><a href="/url">Baz</a></p>

链接文本链接标签 之间不允许出现 空白字符

示例 538试一试
[foo] [bar]

[bar]: /url "title"
<p>[foo] <a href="/url" title="title">bar</a></p>
示例 539试一试
[foo]
[bar]

[bar]: /url "title"
<p>[foo]
<a href="/url" title="title">bar</a></p>

这偏离了 John Gruber 的原版 Markdown 语法描述,该描述显式允许链接文本和链接标签之间存在空格。这使得引用链接与 行内链接 保持一致,根据原版 Markdown 和本规范,行内链接在链接文本后不允许出现空格。更重要的是,它防止了对连续 快捷引用链接 的意外捕获。如果允许链接文本和链接标签之间出现空格,那么在下面我们将得到一个单一的引用链接,而不是两个预期的快捷引用链接。

[foo]
[bar]

[foo]: /url1
[bar]: /url2

(请注意,快捷引用链接 是由 Gruber 本人在 Markdown.pl 的测试版中引入的,但从未包含在官方语法描述中。如果没有快捷引用链接,允许链接文本和链接标签之间出现空格是无害的;但一旦引入快捷引用,允许这样做就太危险了,因为它经常导致意外结果。)

当存在多个匹配的 链接引用定义 时,使用第一个。

示例 540试一试
[foo]: /url1

[foo]: /url2

[bar][foo]
<p><a href="/url1">bar</a></p>

请注意,匹配是在规范化字符串上执行的,而不是在解析的行内内容上。因此,以下内容不匹配,即使标签定义了等效的行内内容。

示例 541试一试
[bar][foo\!]

[foo!]: /url
<p>[bar][foo!]</p>

链接标签 不能包含括号,除非它们经过反斜杠转义。

示例 542试一试
[foo][ref[]

[ref[]: /uri
<p>[foo][ref[]</p>
<p>[ref[]: /uri</p>
示例 543试一试
[foo][ref[bar]]

[ref[bar]]: /uri
<p>[foo][ref[bar]]</p>
<p>[ref[bar]]: /uri</p>
示例 544试一试
[[[foo]]]

[[[foo]]]: /url
<p>[[[foo]]]</p>
<p>[[[foo]]]: /url</p>
示例 545试一试
[foo][ref\[]

[ref\[]: /uri
<p><a href="/uri">foo</a></p>

请注意,在此示例中,] 没有经过反斜杠转义。

示例 546试一试
[bar\\]: /uri

[bar\\]
<p><a href="/uri">bar\</a></p>

链接标签 必须至少包含一个 非空白字符

示例 547试一试
[]

[]: /uri
<p>[]</p>
<p>[]: /uri</p>
示例 548试一试
[
 ]

[
 ]: /uri
<p>[
]</p>
<p>[
]: /uri</p>

折叠引用链接由一个 链接标签 组成,该标签 匹配 文档其他位置的 链接引用定义,后跟字符串 []。第一个链接标签的内容被解析为行内元素,用作链接的文本。链接的 URI 和标题由匹配的引用链接定义提供。因此,[foo][] 等同于 [foo][foo]

示例 549试一试
[foo][]

[foo]: /url "title"
<p><a href="/url" title="title">foo</a></p>
示例 550试一试
[*foo* bar][]

[*foo* bar]: /url "title"
<p><a href="/url" title="title"><em>foo</em> bar</a></p>

链接标签不区分大小写。

示例 551试一试
[Foo][]

[foo]: /url "title"
<p><a href="/url" title="title">Foo</a></p>

与完整引用链接一样,两组括号之间不允许使用 空白字符

示例 552试一试
[foo] 
[]

[foo]: /url "title"
<p><a href="/url" title="title">foo</a>
[]</p>

快捷引用链接由一个链接标签组成,该标签在文档中其它地方匹配到一个链接引用定义,且后面不跟 [] 或链接标签。第一个链接标签的内容被解析为行内元素,用作链接的文本。链接的 URI 和标题由匹配的链接引用定义提供。因此,[foo] 等同于 [foo][]

示例 553试一试
[foo]

[foo]: /url "title"
<p><a href="/url" title="title">foo</a></p>
示例 554试一试
[*foo* bar]

[*foo* bar]: /url "title"
<p><a href="/url" title="title"><em>foo</em> bar</a></p>
示例 555试一试
[[*foo* bar]]

[*foo* bar]: /url "title"
<p>[<a href="/url" title="title"><em>foo</em> bar</a>]</p>
示例 556试一试
[[bar [foo]

[foo]: /url
<p>[[bar <a href="/url">foo</a></p>

链接标签不区分大小写。

示例 557试一试
[Foo]

[foo]: /url "title"
<p><a href="/url" title="title">Foo</a></p>

链接文本后的空格应予以保留。

示例 558试一试
[foo] bar

[foo]: /url
<p><a href="/url">foo</a> bar</p>

如果您只想使用方括号文本,可以对左方括号进行反斜杠转义以避免链接。

示例 559试一试
\[foo]

[foo]: /url "title"
<p>[foo]</p>

请注意,这是一个链接,因为链接标签以第一个随后的闭合方括号结束。

示例 560试一试
[foo*]: /url

*[foo*]
<p>*<a href="/url">foo*</a></p>

完整引用和紧凑引用优先于快捷引用。

示例 561试一试
[foo][bar]

[foo]: /url1
[bar]: /url2
<p><a href="/url2">foo</a></p>
示例 562试一试
[foo][]

[foo]: /url1
<p><a href="/url1">foo</a></p>

内联链接也具有优先权

示例 563试一试
[foo]()

[foo]: /url1
<p><a href="">foo</a></p>
示例 564试一试
[foo](not a link)

[foo]: /url1
<p><a href="/url1">foo</a>(not a link)</p>

在以下情况中,[bar][baz] 被解析为引用,[foo] 被解析为普通文本。

示例 565试一试
[foo][bar][baz]

[baz]: /url
<p>[foo]<a href="/url">bar</a></p>

然而在这里,[foo][bar] 被解析为引用,因为定义了 [bar]

示例 566试一试
[foo][bar][baz]

[baz]: /url1
[bar]: /url2
<p><a href="/url2">foo</a><a href="/url1">baz</a></p>

在这里 [foo] 没有被解析为快捷引用,因为它后面紧跟一个链接标签(即使 [bar] 没有定义)。

示例 567试一试
[foo][bar][baz]

[baz]: /url1
[foo]: /url2
<p>[foo]<a href="/url1">bar</a></p>

6.6图像

图像语法类似于链接语法,但有一点不同。我们拥有的不是 链接文本,而是 图像描述。其规则与 链接文本 相同,除了 (a) 图像描述以 ![ 开头而不是 [,以及 (b) 图像描述可以包含链接。图像描述将行内元素作为其内容。当图像渲染为 HTML 时,这通常用作图像的 alt 属性。

示例 568试一试
![foo](/url "title")
<p><img src="/url" alt="foo" title="title" /></p>
示例 569试一试
![foo *bar*]

[foo *bar*]: train.jpg "train & tracks"
<p><img src="train.jpg" alt="foo bar" title="train &amp; tracks" /></p>
示例 570试一试
![foo ![bar](/url)](/url2)
<p><img src="/url2" alt="foo bar" /></p>
示例 571试一试
![foo [bar](/url)](/url2)
<p><img src="/url2" alt="foo bar" /></p>

尽管本规范关注的是解析而不是渲染,但建议在渲染为 HTML 时,仅使用 图像描述 的纯字符串内容。请注意,在上面的示例中,alt 属性的值是 foo bar,而不是 foo [bar](/url)foo <a href="/url">bar</a>。只有纯字符串内容被渲染,不带任何格式。

示例 572试一试
![foo *bar*][]

[foo *bar*]: train.jpg "train & tracks"
<p><img src="train.jpg" alt="foo bar" title="train &amp; tracks" /></p>
示例 573试一试
![foo *bar*][foobar]

[FOOBAR]: train.jpg "train & tracks"
<p><img src="train.jpg" alt="foo bar" title="train &amp; tracks" /></p>
示例 574试一试
![foo](train.jpg)
<p><img src="train.jpg" alt="foo" /></p>
示例 575试一试
My ![foo bar](/path/to/train.jpg  "title"   )
<p>My <img src="/path/to/train.jpg" alt="foo bar" title="title" /></p>
示例 576试一试
![foo](<url>)
<p><img src="url" alt="foo" /></p>
示例 577试一试
![](/url)
<p><img src="/url" alt="" /></p>

引用式:

示例 578试一试
![foo][bar]

[bar]: /url
<p><img src="/url" alt="foo" /></p>
示例 579试一试
![foo][bar]

[BAR]: /url
<p><img src="/url" alt="foo" /></p>

折叠式:

示例 580试一试
![foo][]

[foo]: /url "title"
<p><img src="/url" alt="foo" title="title" /></p>
示例 581试一试
![*foo* bar][]

[*foo* bar]: /url "title"
<p><img src="/url" alt="foo bar" title="title" /></p>

标签不区分大小写。

示例 582试一试
![Foo][]

[foo]: /url "title"
<p><img src="/url" alt="Foo" title="title" /></p>

与引用链接一样,两组括号之间不允许使用 空白字符

示例 583试一试
![foo] 
[]

[foo]: /url "title"
<p><img src="/url" alt="foo" title="title" />
[]</p>

快捷式:

示例 584试一试
![foo]

[foo]: /url "title"
<p><img src="/url" alt="foo" title="title" /></p>
示例 585试一试
![*foo* bar]

[*foo* bar]: /url "title"
<p><img src="/url" alt="foo bar" title="title" /></p>

请注意,链接标签不能包含未转义的括号。

示例 586试一试
![[foo]]

[[foo]]: /url "title"
<p>![[foo]]</p>
<p>[[foo]]: /url &quot;title&quot;</p>

链接标签不区分大小写。

示例 587试一试
![Foo]

[foo]: /url "title"
<p><img src="/url" alt="Foo" title="title" /></p>

如果你只想显示一个字面意义上的 ! 字符,后跟带括号的文本,你可以对开头的 [ 进行反斜杠转义

示例 588试一试
!\[foo]

[foo]: /url "title"
<p>![foo]</p>

如果您想在字面意义上的 ! 之后使用链接,请对 ! 进行反斜杠转义。

示例 589试一试
\![foo]

[foo]: /url "title"
<p>!<a href="/url" title="title">foo</a></p>

自动链接是位于 <> 之间的绝对 URI 和电子邮件地址。它们被解析为链接,并将 URL 或电子邮件地址作为链接标签。

URI 自动链接<,后跟一个 绝对 URI,再后跟 > 组成。它被解析为指向该 URI 的链接,并将该 URI 作为链接标签。

就此而言,绝对 URI方案、冒号 (:) 以及零个或多个非 ASCII 空白和控制字符、<> 的字符组成。如果 URI 包含这些字符,它们必须进行百分号编码(例如,空格使用 %20)。

就本规范而言,方案是任何以 ASCII 字母开头,后跟 ASCII 字母、数字或加号 (”+”)、句点 (”.”)、连字符 (”-”) 的任意组合的 2–32 个字符的序列。

以下是一些有效的自动链接:

示例 590试一试
<http://foo.bar.baz>
<p><a href="http://foo.bar.baz">http://foo.bar.baz</a></p>
示例 591试一试
<http://foo.bar.baz/test?q=hello&id=22&boolean>
<p><a href="http://foo.bar.baz/test?q=hello&amp;id=22&amp;boolean">http://foo.bar.baz/test?q=hello&amp;id=22&amp;boolean</a></p>
示例 592试一试
<irc://foo.bar:2233/baz>
<p><a href="irc://foo.bar:2233/baz">irc://foo.bar:2233/baz</a></p>

大写字母也可以。

示例 593试一试
<MAILTO:FOO@BAR.BAZ>
<p><a href="MAILTO:FOO@BAR.BAZ">MAILTO:FOO@BAR.BAZ</a></p>

请注意,许多符合本规范定义的 绝对 URI 的字符串并不是有效的 URI,这是因为它们的方案未注册,或者由于其语法存在其他问题

示例 594试一试
<a+b+c:d>
<p><a href="a+b+c:d">a+b+c:d</a></p>
示例 595试一试
<made-up-scheme://foo,bar>
<p><a href="made-up-scheme://foo,bar">made-up-scheme://foo,bar</a></p>
示例 596试一试
<http://../>
<p><a href="http://../">http://../</a></p>
示例 597试一试
<localhost:5001/foo>
<p><a href="localhost:5001/foo">localhost:5001/foo</a></p>

自动链接中不允许出现空格。

示例 598试一试
<http://foo.bar/baz bim>
<p>&lt;http://foo.bar/baz bim&gt;</p>

反斜杠转义在自动链接内不起作用。

示例 599试一试
<http://example.com/\[\>
<p><a href="http://example.com/%5C%5B%5C">http://example.com/\[\</a></p>

一个 电子邮件自动链接<,后跟 电子邮件地址,后跟 > 组成。链接标签为该电子邮件地址,URL 为 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])?)*$/

电子邮件自动链接示例:

示例 600试一试
<foo@bar.example.com>
<p><a href="mailto:foo@bar.example.com">foo@bar.example.com</a></p>
示例 601试一试
<foo+special@Bar.baz-bar0.com>
<p><a href="mailto:foo+special@Bar.baz-bar0.com">foo+special@Bar.baz-bar0.com</a></p>

反斜杠转义在电子邮件自动链接内不起作用。

示例 602试一试
<foo\+@bar.example.com>
<p>&lt;foo+@bar.example.com&gt;</p>

这些不是自动链接:

示例 603试一试
<>
<p>&lt;&gt;</p>
示例 604试一试
< http://foo.bar >
<p>&lt; http://foo.bar &gt;</p>
示例 605试一试
<m:abc>
<p>&lt;m:abc&gt;</p>
示例 606试一试
<foo.bar.baz>
<p>&lt;foo.bar.baz&gt;</p>
示例 607试一试
http://example.com
<p>http://example.com</p>
示例 608试一试
foo@bar.example.com
<p>foo@bar.example.com</p>

6.8原生 HTML

<> 之间看起来像 HTML 标签的文本会被解析为原始 HTML 标签,并将直接在 HTML 中渲染而不会进行转义。标签和属性名称不限于当前的 HTML 标签,因此可以使用自定义标签(甚至可以例如使用 DocBook 标签)。

这是标签语法:

标签名称由一个 ASCII 字母开头,后跟零个或多个 ASCII 字母、数字或连字符(-)。

一个 属性空白属性名称 和可选的 属性值规范 组成。

属性名称由 ASCII 字母、_: 开头,后跟零个或多个 ASCII 字母、数字、_.:-。(注意:这是受限于 ASCII 的 XML 规范。HTML5 则更宽松。)

一个 属性值规范 由可选的 空白= 字符、可选的 空白属性值 组成。

一个 属性值无引号属性值单引号属性值双引号属性值 组成。

无引号属性值是一个非空的字符字符串,不包含空白字符"'=<>`

单引号属性值'、零个或多个不包含 ' 的字符,以及一个最后的 ' 组成。

双引号属性值"、零个或多个不包含 " 的字符,以及一个最后的 " 组成。

开始标签由一个 < 字符、一个标签名、零个或多个属性、可选空白、一个可选的 / 字符和一个 > 字符组成。

一个 结束标签 由字符串 </标签名称、可选的 空白 以及 > 字符组成。

HTML 注释<!-- + 文本 + --> 组成,其中 文本 不能以 >-> 开头,不能以 - 结尾,且不能包含 --。(参见 HTML5 规范。)

一个 处理指令 (processing instruction) 由字符串 <?、一段不包含字符串 ?> 的字符序列,以及字符串 ?> 组成。

一个 声明 (declaration) 由字符串 <!、一个由一个或多个大写 ASCII 字母组成的名称、空白字符、一段不包含字符 > 的字符序列,以及字符 > 组成。

一个 CDATA 部分 (CDATA section) 由字符串 <![CDATA[、一段不包含字符串 ]]> 的字符序列,以及字符串 ]]> 组成。

一个 HTML 标签开始标签结束标签HTML 注释处理指令声明CDATA 节 组成。

以下是一些简单的开始标签

示例 609试一试
<a><bab><c2c>
<p><a><bab><c2c></p>

空元素

示例 610试一试
<a/><b2/>
<p><a/><b2/></p>

允许使用 空白字符

示例 611试一试
<a  /><b2
data="foo" >
<p><a  /><b2
data="foo" ></p>

带有属性

示例 612试一试
<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>

可以使用自定义标签名称

示例 613试一试
Foo <responsive-image src="foo.jpg" />
<p>Foo <responsive-image src="foo.jpg" /></p>

非法标签名称,不会被解析为 HTML

示例 614试一试
<33> <__>
<p>&lt;33&gt; &lt;__&gt;</p>

非法属性名称

示例 615试一试
<a h*#ref="hi">
<p>&lt;a h*#ref=&quot;hi&quot;&gt;</p>

非法属性值

示例 616试一试
<a href="hi'> <a href=hi'>
<p>&lt;a href=&quot;hi'&gt; &lt;a href=hi'&gt;</p>

非法 空白字符

示例 617试一试
< a><
foo><bar/ >
<foo bar=baz
bim!bop />
<p>&lt; a&gt;&lt;
foo&gt;&lt;bar/ &gt;
&lt;foo bar=baz
bim!bop /&gt;</p>

缺失 空白字符

示例 618试一试
<a href='bar'title=title>
<p>&lt;a href='bar'title=title&gt;</p>

结束标签

示例 619试一试
</a></foo >
<p></a></foo ></p>

结束标签中的非法属性

示例 620试一试
</a href="foo">
<p>&lt;/a href=&quot;foo&quot;&gt;</p>

注释

示例 621试一试
foo <!-- this is a
comment - with hyphen -->
<p>foo <!-- this is a
comment - with hyphen --></p>
示例 622试一试
foo <!-- not a comment -- two hyphens -->
<p>foo &lt;!-- not a comment -- two hyphens --&gt;</p>

非注释

示例 623试一试
foo <!--> foo -->

foo <!-- foo--->
<p>foo &lt;!--&gt; foo --&gt;</p>
<p>foo &lt;!-- foo---&gt;</p>

处理指令

示例 624试一试
foo <?php echo $a; ?>
<p>foo <?php echo $a; ?></p>

声明

示例 625试一试
foo <!ELEMENT br EMPTY>
<p>foo <!ELEMENT br EMPTY></p>

CDATA 部分

示例 626试一试
foo <![CDATA[>&<]]>
<p>foo <![CDATA[>&<]]></p>

HTML 属性中的实体引用和数字字符引用会被保留

示例 627试一试
foo <a href="&ouml;">
<p>foo <a href="&ouml;"></p>

反斜杠转义在 HTML 属性中无效

示例 628试一试
foo <a href="\*">
<p>foo <a href="\*"></p>
示例 629试一试
<a href="\"">
<p>&lt;a href=&quot;&quot;&quot;&gt;</p>

6.9硬换行

一个在代码块或 HTML 标签之外的换行,如果其前面有两个或更多空格,且不位于块的末尾,则被解析为 硬换行(在 HTML 中渲染为 <br /> 标签)。

示例 630试一试
foo  
baz
<p>foo<br />
baz</p>

作为一种更直观的替代方案,可以在 行尾 之前使用反斜杠来代替两个空格

示例 631试一试
foo\
baz
<p>foo<br />
baz</p>

可以使用超过两个的空格

示例 632试一试
foo       
baz
<p>foo<br />
baz</p>

下一行开头的空格会被忽略

示例 633试一试
foo  
     bar
<p>foo<br />
bar</p>
示例 634试一试
foo\
     bar
<p>foo<br />
bar</p>

换行符可以出现在强调、链接以及其他允许内联内容的结构中

示例 635试一试
*foo  
bar*
<p><em>foo<br />
bar</em></p>
示例 636试一试
*foo\
bar*
<p><em>foo<br />
bar</em></p>

换行符不会出现在代码行内

示例 637试一试
`code 
span`
<p><code>code  span</code></p>
示例 638试一试
`code\
span`
<p><code>code\ span</code></p>

或者 HTML 标签内

示例 639试一试
<a href="foo  
bar">
<p><a href="foo  
bar"></p>
示例 640试一试
<a href="foo\
bar">
<p><a href="foo\
bar"></p>

硬换行用于分隔块内的内联内容。两种硬换行语法在段落或其他块元素的末尾均无效

示例 641试一试
foo\
<p>foo\</p>
示例 642试一试
foo  
<p>foo</p>
示例 643试一试
### foo\
<h3>foo\</h3>
示例 644试一试
### foo  
<h3>foo</h3>

6.10软换行

一个常规的换行符(不在代码行或 HTML 标签中),且未被两个或更多空格或反斜杠前置,被解析为软换行。(软换行在 HTML 中可以渲染为行尾或空格。结果在浏览器中是一样的。在此处的示例中,将使用行尾。)

示例 645试一试
foo
baz
<p>foo
baz</p>

行末和下一行开头的空格会被移除

示例 646试一试
foo 
 baz
<p>foo
baz</p>

符合标准的解析器可以将 HTML 中的软换行渲染为换行符或空格。

渲染器也可以提供一个选项,将软换行渲染为硬换行。

6.11文本内容

上述规则未定义的任何字符将被解析为普通文本内容。

示例 647试一试
hello $.;'there
<p>hello $.;'there</p>
示例 648试一试
Foo χρῆν
<p>Foo χρῆν</p>

内部空格会被逐字保留

示例 649试一试
Multiple     spaces
<p>Multiple     spaces</p>

附录:一种解析策略

在本附录中,我们描述了 CommonMark 参考实现中所使用的解析策略的一些特性。

概述

解析分为两个阶段

  1. 第一阶段,消耗输入行并构建文档的块结构——即将其划分为段落、块引用、列表项等。文本被分配给这些块,但不进行解析。链接引用定义会被解析并构建一个链接映射表。

  2. 第二阶段,段落和标题的原始文本内容被解析为 Markdown 内联元素序列(字符串、代码行、链接、强调等),并使用第一阶段构建的链接引用映射表。

在处理的每个点,文档都被表示为由组成的树。树的根是 document 块。document 可以拥有任意数量的其他块作为子节点。这些子节点依次又可以拥有其他块作为子节点。块的最后一个子节点通常被视为开放的,意味着后续的输入行可以改变其内容。(未开放的块即为已关闭的。)例如,这是一个可能的文档树,箭头标记了开放的块

-> 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. 一个或多个开放的块可能会被关闭。
  2. 一个或多个新的块可能会作为最后一个开放块的子节点被创建。
  3. 文本可以被添加到树上最后一个(最深层的)开放块中。

一旦某一行以这种方式被合并到树中,它就可以被丢弃,因此输入可以以流的形式读取。

对于每一行,我们遵循以下程序

  1. 首先,我们遍历开放的块,从根文档开始,沿最后一个子节点向下,直到最后一个开放块。每个块都施加了一个条件,如果要保持块开放,该行必须满足该条件。例如,块引用要求有 > 字符。段落要求非空行。在这个阶段,我们可能匹配所有或部分开放的块。但我们还不能关闭不匹配的块,因为我们可能遇到了惰性延续行

  2. 接下来,在消耗现有块的延续标记后,我们寻找新的块开始(例如,用于块引用的 >)。如果我们遇到一个新的块开始,我们将在创建新块作为最后一个匹配块的子块之前,关闭步骤 1 中未匹配的任何块。

  3. 最后,我们查看该行的剩余部分(在消耗了块标记如 >、列表标记和缩进之后)。这些文本可以被合并到最后一个开放块中(段落、代码块、标题或原始 HTML)。

当看到段落中属于 Setext 标题下划线 的一行时,就会形成 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 设为 NULL。

从分隔符栈的顶部开始,我们向后查找打开的 [![ 分隔符。

处理强调

参数 stack_bottom 为我们在 分隔符栈 中下降的深度设置了一个下限。如果它是 NULL,我们可以一直下降到栈底。否则,我们在访问 stack_bottom 之前停止。

current_position 指向 分隔符栈stack_bottom 之上的元素(如果 stack_bottom 为 NULL,则指向第一个元素)。

我们追踪每种定界符类型(*, _)和每个关闭定界符序列长度(模 3)的 openers_bottom。将其初始化为 stack_bottom

然后我们重复以下操作,直到耗尽所有潜在的结束符:

完成之后,我们从分隔符栈中移除 stack_bottom 之上的所有分隔符。