Markdown虽然很流行,但是其实是一种非常松散的语言,没有统一的标准。于是就有各种版本的Markdown,比如有kramdownvfmd还有今天要介绍的commonmark。一般来说,先有一个Markdown的解释器,然后这个解释器开发过程中发现当前的Markdown语法表达能力不够,于是就开始扩展,就有了这种Markdown的方言。

commonmark是一个强定义的Markdown规范,意味着它会对很多细节做出定义,避免歧义性,这样一来,写Markdown解释器和转换器就比较简单了。Learn Markdown in 60 Seconds可以快速帮你一览commonmark的样貌。commonmark dingus可以让你尝试在线书写Markdown并观察其效果。

commonmark spec规范是commonmark定义之所在。目前规范的版本是0.29 (2019-04-06)commonmark code则是此规范的标准实现。

平铺类型

Emphasis 和 strong emphasis

6.4Emphasis and strong emphasis

通常在Markdown里面如果用一个*来包围其他字符,表示以strong的方式(通常是加粗)突出这些字符;如果是以两个*来包围其他字符,则表示以emphasis(通常是斜体)的方式来强调这些字符。

但是嵌套的情况怎么处理呢?比如字符两边有若干个*环绕,应该如何处置?

Markdown发明者John Gruber最初是这么说的:

Markdown treats asterisks (*) and underscores (_) as indicators of emphasis. Text wrapped with one * or _ will be wrapped with an HTML <em> tag; double *’s or _’s will be wrapped with an HTML <strong> tag.

本来想在这篇文章中详细说明一些,Emphasis 和 strong emphasis的规则。后来一看,一共有十七条规则,并且举了130个例子来说明这些规则,实在没有办法在此一一列举了。所以下面就以非常不精确的语言来描述以下:

  • *_都可以用来突出(emphasis),这两者最大的区别是在在单词中的表现,5*6*78中的6会被突出,而5_6_78中的6不会被突出,因为_被视作单词的一部分。
  • *_不能混合使用,不能一个开头以另一个结尾。
  • *_和其所围绕的单词之间不能有空格。
  • *_对字符和标点符号有所区分对待,夹在字符和标点符号之间的多个*_优先作用于字符。
  • 两个*_表示强调(strong)。超过两个以上的,表示突出强调。注意,一定是突出在前面,强调在后面,对应html的<em><strong></strong></em>
  • 对于间隔出现的多组*_,采用优先匹配,最短匹配的原则。
  • *_的效用要比平铺代码串(code)、链接(link)、图片(image)和HTML标签弱

在实际解析中,CommonMark用两个概念:左肋界定群(left-flanking delimiter run)和右肋界定群(right-flanking delimiter run)来协助解析的处理。这两个概念比较复杂,就不翻译了,原文照搬如下:

First, some definitions. A delimiter run is either a sequence of one or more * characters that is not preceded or followed by a non-backslash-escaped * character, or a sequence of one or more _ characters that is not preceded or followed by a non-backslash-escaped _ character.

A left-flanking delimiter run is a delimiter run that is (1) not followed by Unicode whitespace, and either (2a) not followed by a punctuation character, or (2b) followed by a punctuation character and preceded by Unicode whitespace or a punctuation character. For purposes of this definition, the beginning and the end of the line count as Unicode whitespace.

A right-flanking delimiter run is a delimiter run that is (1) not preceded by Unicode whitespace, and either (2a) not preceded by a punctuation character, or (2b) preceded by a punctuation character and followed by Unicode whitespace or a punctuation character. For purposes of this definition, the beginning and the end of the line count as Unicode whitespace.

(完)