このページの内容

1はじめに

1.1Markdownとは

Markdownは構造化された文書を書くためのプレーンテキスト形式で、電子メールやUsenetへの投稿で書式を示す慣習に基づいています。John GruberがAaron Swartzの協力を得て開発し、2004年に構文の説明と、MarkdownをHTMLに変換するPerlスクリプト(Markdown.pl)として公開しました。その後の10年間で、さまざまな言語による数十もの実装が開発されました。元のMarkdown構文に、脚注、表、その他の文書要素の記法を追加したものもあります。Markdown文書をHTML以外の形式で表示できるようにしたものもあります。Reddit、StackOverflow、GitHubのようなウェブサイトでは、何百万人もの人がMarkdownを使っていました。そしてMarkdownは、ウェブ以外でも、書籍、記事、スライド、手紙、講義ノートの執筆に使われるようになりました。

Markdownを、より書きやすい場合も多いほかの軽量マークアップ構文と区別するのは、読みやすさです。Gruberは次のように述べています。

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版のほうがはるかに読みやすくなっています。リスト項目の入れ子が、処理後の文書だけでなく、ソースを見てもわかります。

1.2仕様が必要な理由

John GruberによるMarkdown構文の原著の説明では、構文が曖昧さなく定義されていません。そこでは答えが示されていない問いの例を挙げます。

  1. 子リストにはどれだけの字下げが必要でしょうか。説明では、続きの段落に4個のスペースで字下げする必要があるとされていますが、子リストについては十分に明示されていません。子リストにも4個のスペースが必要だと考えるのは自然ですが、Markdown.plはそれを要求しません。これは「特殊な端のケース」とはいいがたく、この点で実装が異なるため、実際の文書で利用者が意外な結果に遭遇することはよくあります。(John Gruberのこのコメントを参照してください。)

  2. ブロック引用や見出しの前に空行は必要でしょうか。ほとんどの実装では必要ありません。しかし、テキストに明示的な改行を入れて行を折り返していると、予期しない結果を生んだり、解析に曖昧さが生じたりします。見出しをブロック引用の内側に入れる実装もあれば、入れない実装もある点に注意してください。(John Gruberも空行を必須にすることを支持する発言をしています。)

  3. 字下げによるコードブロックの前に空行は必要でしょうか。(Markdown.plは空行を要求しますが、文書にはそのことが書かれておらず、要求しない実装もあります。)

    paragraph
        code?
    
  4. リスト項目を<p>タグで囲むかどうかを決める正確な規則は何でしょうか。1つのリストが、一部は「loose」、一部は「tight」になれるのでしょうか。次のようなリストはどう扱うべきでしょうか。

    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. これは、2番目の項目に主題区切りが入った1つのリストでしょうか。それとも、主題区切りで分けられた2つのリストでしょうか。

    * a
    * * * * *
    * b
    
  7. リストのマーカーが数字から箇条書き記号に変わったとき、リストは2つになるのでしょうか、それとも1つでしょうか。(Markdown構文の説明では2つになるように示されていますが、Perlスクリプトや多くのほかの実装では1つになります。)

    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を使えば、抽象構文木を出力するレンダラーを新たに書かずに、実装に対して試験を実行できます。

HTMLの例に現れるすべての特徴を、仕様が要求しているわけではない点に注意してください。たとえば、仕様は何がリンク先にあたるかを定めていますが、URL中の非ASCII文字をパーセント符号化することまでは要求していません。自動試験を利用する場合、実装者は仕様の例の期待結果に合うレンダラー、つまりURL中の非ASCII文字をパーセント符号化するレンダラーを用意する必要があります。しかし、仕様に適合する実装は別のレンダラーを使ってもよく、URL中の非ASCII文字をパーセント符号化しないことを選んでもかまいません。

この文書は、Markdownに対照試験用の小さな拡張を加えて書かれたテキストファイルspec.txtから生成されます。スクリプトtools/makespec.pyを使うと、spec.txtをHTMLまたはCommonMarkに変換できます。後者はさらにほかの形式へ変換できます。

例では、→という文字でタブを表します。