|

2023-10-26

Tips

Markdownで「カギ括弧」に強調を入れても機能しない条件を知っているか

Markdown仕様

Markdownで強調を入れたいときにカギ括弧が絡んだらどうするべきか

Markdownでの強調が…効かない?

早速ですが、問題です。下の画像を見てください。

  Untitled

 

Visual Studio CodeにMarkdownを解釈して貰って、勝手に強調表示される予定のものは強調表示されるようにしてあります。

 

なぜ2つめ(3行目)の 明日は**「晴れ」**でしょう。 は強調が効いていないか、即答できる人はこの世にどれだけいるものでしょうか…

 

Markdownの方言

まず第一に、こういった不可解な動作を調べるときは必ず「仕様」を当たるところから入っていくと思いますが、Markdownの仕様って結構乱立しているんですよね。

 

本筋と違う話なのですごいザックリな説明ですが、「CommonMark」が可能な限り標準化を目指している仕様であり、それを拡張しているのがGitHub Flavored Markdown(GFM)であるということで、このあたりがデファクトスタンダードに近いものになるかと思います。

拡張内容を具体的に言うと、GFMではTable等の仕様が足されています。やっぱりTableは欲しいですよね。

 

で、今回これを調べるにあたり、結構真面目に仕様書(Spec)を読んでみたのですが、このSpec自体が思いのほか面白かったのでとりあえずリンクを張っておきます。(今日の話の結論だけはよ解説してくれ、という話であれば特に見る必要は無いです)

 

 

特にGFMのSpecページは何が拡張されているかがとてもわかりやすいのでめちゃくちゃ良いと思います。 GitHub_Flavored_Markdown_Spec_2023-10-24_15-37-36

 

今回は拡張前の仕様にも含まれている強調にフォーカスしていますので、CommonMarkのSpecに沿って話を進めます。

 

鍵はPunctuation Characterの扱いにある

まず、鍵を握っているのはPunctuation Characterです。

 

Punctuation Characterとは?

CommonMarkのSpecの2.1には

An ASCII punctuation character is !, ", #, $, %, &, ', (, ), *, +, ,, -, ., / (U+0021–2F), :, ;, <, =, >, ?, @ (U+003A–0040), [, , ], ^, _, ` (U+005B–0060), {, |, }, or ~ (U+007B–007E).

A Unicode punctuation character is an ASCII punctuation character or anything in the general Unicode categories Pc, Pd, Pe, Pf, Pi, Po, or Ps.

と記載があります。

まあ要するに、句読点や括弧のような記号を包括している…くらいの認識でとりあえずは大丈夫だと思います。

 

強調の仕様を紐解く

準備も整ってきたので、ちゃんと強調の仕様を紐解きます。

CommonMarkのSpecの6.2 Emphasis and strong emphasisを読んでみます。

 

delimiter run

まず理解のために必要なのは delimtier run です。

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.

要するに、 * あるいは _ の連続文字列であるということですね

 

その上で、 left-flanking delimiter run というものがあって、これは、行頭および行末は空白として考えたうえで

  • (1) 空白が後に続かない

  • (2) 下記のいずれかを満たす

    • (2a) Punctuation Characterが後に続かない

    • (2b) 前にPunctuation Characterか空白があってPunctuation Characterが後に続く

の両条件を満たすものになります。

 

さらに right-flanking delimtier run というものがあり、

  • (1) 空白が先行していない

  • (2) 下記のいずれかを満たす

    • (2a) Punctuation Characterが先行していない

    • (2b) 後にPunctuation Characterか空白があってPunctuation Characterが先行している

の両条件を満たすものとなっています。

 

強調の仕様

そして、続きに強調のルールについて記述があります

A double ** can open strong emphasis iff it is part of a left-flanking delimiter run.

A double ** can close strong emphasis iff it is part of a right-flanking delimiter run.

つまり、 left-flanking で開いて right-flanking で閉じてはじめて強調されるということです。

これが強調の仕様です。

(今回の謎に関係するところだけ引っ張ってありますがもっと細かいことも色々書いてありますので興味があったらぜひ参照すると良いと思います)

 

Markdown強調の謎、解明

そしていよいよ決着の時です。

明日は**「晴れ」**でしょう。

これを見てみましょう。

 

まず、 といった括弧はPunctuation Characterです。

 

そして、2つの ** は連続しているのでいずれも delimtier run です。

いずれも空白が先行も後に続いてもいませんが、

「Punctuation Characterが先行していない」のが1つめのほうで、

「Punctuation Characterが後に続かない」のが2つめのほうになっています。

 

つまり、1つめの **right-flanking であり、2つめの **left-flanking なわけです。

 

だから結局は、 明日は**「晴れ」**でしょう。 という文にしてしまうと最初の ** は閉じるほうになっていて、最後の ** は開くほうになっている、つまり思っていたものと逆になってしまっているわけなので狙い通りの強調が出来ないということになります。

 

だから、さらに後に ** を付けると、後ろの2つの ** に囲まれた部分だけが閉じられる形で強調されます。 Untitled

 

では、カギ括弧の前後に空白を入れてみて、

明日は **「晴れ」** でしょう。

はどうでしょうか?

  • 1つめの ** は「空白が先行していない」を満たしていないので left-flanking

  • 2つめの ** は「空白が後に続かない」を満たしていないので right-flanking

となります。※(2)の条件はどちらも満たしています。

 

よって、1つめで開いて2つめで閉じられているので狙い通りの強調となっている、というわけです。

 

狙い通りに強調を行うための対策

全員に常に何が left-flanking でなにが right-flanking かを理解しましょう…と伝えるのはなかなかしんどいものの、Markdownはもはや日常生活で欠かせないものかとも思うので、現実的にどう対処すれば良いのかも考えておきましょう。

 

ひとつは強調したいときは前後に空白を入れるようにするのが一番手っ取り早いかもしれません。

もうひとつは括弧や記号が現れたら強調時には前後に空白をいれるよう徹底するその内側で強調を入れる…ということになるかと思います。 Untitled

というわけです。

 

まとめ

今回はMarkdownの意外と知られていない仕様の落とし穴を深掘りしてみました。

当たり前のように使っているもので知らない落とし穴があるとちょっと面白いですよね。

Markdownは何より簡単なのが売りな言語なので、CommonMarkの仕様書レベルであればそこまでヘビーでもなくて読みやすいですね!

ぜひ、秋の夜長にオススメします。(私は睡眠のほうが大事ですが)

 


この記事の著者

プロフィール画像

伴 拓也

朝日放送グループホールディングス株式会社 DX・メディアデザイン局 デジタル・メディアチーム

アプリケーションからインフラ、ネットワーク、データエンジニアリングまで幅広い守備範囲が売り。最近はデータ基盤の構築まわりに力を入れて取り組む。 主な実績として、M-1グランプリ敗者復活戦投票システムのマルチクラウド化等。