Slide 1

Slide 1 text

なぜ強調表⽰できず ** が表⽰されるのか — Perlで始まったMarkdownの歴史と ⽇本語⽂書における課題 hkws / 2025.11.14 YAPC:Fukuoka 2025

Slide 2

Slide 2 text

⾃⼰紹介 ● hkws(かわせ)と⾔います ● 通信系の会社でWebアプリケーション開発を10年くらいやってます ● 副業で 書籍 x LLM なプロダクトの開発をしています ● YAPC初参加です。よろしくお願いします!

Slide 3

Slide 3 text

これ、よく⾒ませんか?

Slide 4

Slide 4 text

これ、よく⾒ませんか? ちゃんと強調できている箇所もある 強調できてない?

Slide 5

Slide 5 text

どんなデータをもとにレンダリングされているのか? Markdownをレンダリングしており、どちらも “**” で強調されている ※ 見やすさのために適宜改行を入れている

Slide 6

Slide 6 text

どんなmarkdownテキストの時に強調表⽰に失敗するのか ● 失敗パターン ○ 開始側の"**"の後が鉤括弧である(私は**「あれ**と⾔った) ○ 終了側の"**"の前が鉤括弧である(私は**あれ」**と⾔った) ● 失敗しそうなのに成功するパターン ○ 開始側の"**"の後が鉤括弧、前がスペース(私は **「あれ**と⾔った) ○ 終了側の"**"の前が鉤括弧、後がスペース(私は**あれ」** と⾔った) ● スペースがあっても失敗するパターン ○ "**" をスペースで囲んでいる場合(私は ** あれ**と⾔った)

Slide 7

Slide 7 text

強調表⽰に失敗する原因 ● 原因は Markdown の仕様化を⽬指す CommonMark の仕様に由来 ● CommonMark は強調表⽰の仕様だけでもルールが17ある ● しかも未解決のケースがある:Issue ● 単に “*” や “**” で囲まれた箇所を にしてくれればいいの に、なんでそんなにややこしいことになっているのか?

Slide 8

Slide 8 text

Markdownの始まりと強調仕様の変遷

Slide 9

Slide 9 text

Markdownの始まり ● John Gruber⽒を中⼼に規定された、Webライター向けのテキストからHTML へ変換するための ○ プレーンテキストをフォーマットする構⽂ ○ プレーンテキストをHTMLに変換するPerlスクリプト: Markdown.pl HTML is a publishing format; Markdown is a writing format. ● 読みやすく書きやすいプレーンテキスト形式で記述し、それを構造的に有効 なHTMLに変換できる

Slide 10

Slide 10 text

The overriding design goal for Markdown’s formatting syntax is to make it as readable as possible. The idea is that a Markdown-formatted document should be publishable as-is, as plain text, without looking like it’s been marked up with tags or formatting instructions. While Markdown’s syntax has been influenced by several existing text-to-HTML filters, the single biggest source of inspiration for Markdown’s syntax is the format of plain text email. オリジナルのMarkdownの思想 Markdownの書式設定構⽂の最⼤の設計⽬標は、可能な限り読みやすくすることです。Markdownで フォーマットされた⽂書は、タグや書式指定でマークアップされているようには⾒えず、プレーンテキス トとしてそのまま公開できるべきであるという考え⽅です。Markdownの構⽂は、既存のテキストから HTMLに変換するフィルターから影響を受けていますが、Markdown構⽂の最⼤のインスピレーション源 は、プレーンテキストメールのフォーマットです。 John Gruber https://daringfireball.net/projects/markdown/

Slide 11

Slide 11 text

オリジナルのMarkdownの課題 ● 細部が未定義 -> 実装が異なるツールが乱⽴し、 互換性が⽋如 ○ Stack OverflowやGithub等、各社で独⾃に改良して実装 ○ Babelmarkにより22個ものMarkdown Parserの出⼒を⽐ 較すると、出⼒が15種類にもなった例もあった ○ In Markdown, we literally built a Tower of Babel
 ● 2004年を最後に、John Gruber⽒によるメンテ ナンスが停⽌

Slide 12

Slide 12 text

CommonMarkプロジェクトの発⾜ 2009年12⽉、Jeff Atwood⽒がMarkdownにおけるリーダーシップの不在を指摘 As Markdown’s “parent,” John has a few key responsibilities in shepherding his baby to maturity. Namely, to lead. To set direction. Beyond that initial 2004 push, he’s done precious little of either. Markdownの「親」として、ジョンには我が⼦を成熟へ⾄らせるための重要な責 任がいくつかある。それは、導くことと、⽅向性を⽰すことだ。2004年の最初の 試みを除けば、彼はそのどちらにもほとんど貢献していない。 Jeff Atwood https://blog.codinghorror.com/responsible-open-source-code-parenting/

Slide 13

Slide 13 text

CommonMarkプロジェクトの発⾜ ● 2012年10⽉、Jeff Atwood⽒によりMarkdownの標準仕様とテストスイート の策定を提案 ● Github, Reddit, Stack Exchange, オープンソースコミュニティの主要メン バーで⾮公開のワーキンググループを発⾜ ● 2014年9⽉、 Standard Markdown としてPublic Review ● John Gruber⽒より、プロジェクト名に "Markdown" を含めることは許容で きないと通達 -> CommonMarkとしてスタート

Slide 14

Slide 14 text

I have appealed to existing conventions and considerations of simplicity, readability, expressive power, and consistency. I have tried to ensure that “normal” documents in the many incompatible existing implementations of markdown will render, as far as possible, as their authors intended. And I have tried to make the rules for different elements work together harmoniously. 決定にあたっては、既存の慣習や、簡潔性、可読性、表現⼒、⼀貫性といった観点を重視しました。互換 性のない多くの既存の markdown 実装における「通常の」⽂書が、可能な限り作成者の意図どおりに表 ⽰されるように努めました。また、異なる要素のルールが調和して機能するように努めました。 CommonMarkの思想 -> オリジナルのMarkdownの思想、および既存のmarkdown⽂書との互換性を保ちつつ、曖 昧さを排除するように策定 John MacFarlane https://blog.codinghorror.com/standard-flavored-markdown/ https://johnmacfarlane.net/beyond-markdown.html

Slide 15

Slide 15 text

● プレーンテキストとしても公開できる、⼈間にとっての読みやすさ書きやす さを重視した、仕様が寛⼤なオリジナルのMarkdown ● オリジナルのMarkdownを尊重しつつ、仕様の曖昧さを無くそうとする CommonMark ● では、強調”**”はオリジナルのMarkdownではどう処理されていて、それを CommonMarkはどう仕様化しようとしたのか? ⼤まかな流れ

Slide 16

Slide 16 text

● Markdownでは、2種類の強調がある ○ 強調: “*”または”_”で囲まれた部分をタグに置換 ○ 強い強調: “**”または”__”で囲まれた部分をタグに置換 ● ⾔葉の定義 ○ 約物: ⽂や語句を区切ったり、省略‧強調したり、また記述を代⽤させるために⽤ いられる句読記号、括弧類など ■ 厳密には、ASCII punctuation characterおよびUnicode punctuation character ○ マーカー: “*”, “_”, “**”, “__”のような、強調の開始/終了を意味する記号(列) 話のための準備

Slide 17

Slide 17 text

強調表⽰の仕様の変遷 - Markdown.pl オリジナルのMarkdown.plでは、以下のサブルーチンでの変換 を⾏う

Slide 18

Slide 18 text

強調表⽰の仕様の変遷 - Markdown.pl の処理後を処理するため、の処理では中⾝の余分な*や_ を飲み込んでいる ● ** や __ の内部の * や _ を許容する ● 中⾝の先頭/末尾は空⽩以外

Slide 19

Slide 19 text

強調表⽰の仕様の変遷 - v0.13以前の強調表⽰の仕様 CommonMarkでは、オリジナルを尊重して以下のように強調表⽰を仕様化 1. 単⼀の"*"は、その後に空⽩が続かない限り、強調を開始できる 3. 単⼀の"*"は、その前に空⽩がない限り、強調を閉じることができる 5. ⼆重の"**"は、その後に空⽩が続かない限り、強い強調を開始できる 7. ⼆重の"**"は、その前に空⽩がない限り、強調を閉じることができる 13. ネスト数は最⼩限に抑える。例えば、 ...の解釈は、 ...という解釈よりも常に優先される

Slide 20

Slide 20 text

強調表⽰の仕様の変遷 - の中のの問題 ネストを許容した前述の仕様は、開き/閉じが不定になるケースがあることが判明 実装によっては期待しない出⼒になってしまった Markdownテキスト: 期待する出⼒: CommonMark v0.13時点でのTryページの実装: 以下のどちらにも当てはまる 1. 単一の"*"は、その後に空白が続かない限り、強調を開始できる 3. 単一の"*"は、その前に空白がない限り、強調を閉じることができる

Slide 21

Slide 21 text

"*"前後の空⽩だけでなく、約物も考慮した形式で強調表⽰を定義 ● 強調表⽰の開始 = left-flanking delimiter ○ 約物 -> マーカー -> 空⽩でも約物でもない⽂字 ○ 空⽩ -> マーカー -> 約物 ● 強調表⽰の終了 = right-flanking delimiter ○ 空⽩でも約物でもない⽂字 -> マーカー -> 約物 ○ 約物 -> マーカー -> 空⽩ 強調表⽰の仕様の変遷 - left/right-flankingの導⼊ These are “**strongly emphasized**” words 白:空白 赤:マーカー 黄:非空白・非約物  青:約物 left-flanking right-flanking These are **“strongly emphasized”** words (*Gomphocarpus 強調の開始にだけマッチ!

Slide 22

Slide 22 text

強調表⽰の仕様の変遷 - left/right-flanking 平たく⾔うと以下の条件(マーカーとして"**"を想定) ● 強調表⽰の開始 ○ "**" の直後が空⽩または約物でない または ○ "**" の直後が約物で、"**" の直前が空⽩または約物 ● 強調表⽰の終了 ○ "**" の直前が空⽩または約物でない または ○ "**" の直前が約物で、"**" の直後が空⽩または約物

Slide 23

Slide 23 text

なぜ⽇本語だと強調表⽰に失敗するのか 分かち書き(語の区切りに空⽩を挟んで記述すること)をしない⾔語は、 強調開始時:"**" の直後が約物で、"**" の直前が空⽩または約物 強調終了時:"**" の直前が約物で、"**" の直後が空⽩または約物 というルールが⾃然に満たされない Time **(really)** flies 空白→マーカー→約物:OK! 私は**「あれ」**と言った 直前に空白がない:NG! 英語:分かち書きする 日本語:分かち書きしない

Slide 24

Slide 24 text

⽇本語等いくつかの⾔語(CJK: Chinese, Japanese, Korean)で空⽩による強調 の開始/終了判定が適⽤できないという課題は、2017年から議論されている ● Emphasis and East Asian text ● Emphasis with CJK punctuation 現在有⼒な解決策は、(すごくざっくり⾔うと)マーカーの直後が⾮CJK約物 で、直前がCJK⽂字であれば、left-flankingとして扱うというもの CommonMarkにおける現在の検討状況 これは強調を”**開始**”可能 これも強調を**”開始”**可能 赤:マーカー 黄:CJK文字 青:非CJK約物

Slide 25

Slide 25 text

● Markdown Parser/Rendererを組み込んだアプリケーション開発者が採⽤で きる対策 ○ CJK friendlyな実装が組み込まれたParser/Rendererを利⽤する(例: Comrak) ○ CJK friendlyなプラグインを利⽤する(例:remark-cjk-friendly) 現状できる対策 ● markdownでの⽂書作成ユーザが採⽤できる対策 ○ 開始時は空⽩ -> マーカー -> 約物、終了時は約物 -> マーカー -> 空⽩となるように ⽂書を書く ○ ⽣HTMLを書く

Slide 26

Slide 26 text

CommonMarkにおけるその他の⽇本語の問題

Slide 27

Slide 27 text

CommonMarkには以下のようなソフト改⾏の説明がある ソフト改⾏(Soft line break)の説明 これについて、以下の点が指摘されている ● “ソフト改⾏はHTMLで改⾏またはスペースとしてレンダリングされうる”は不明瞭 ● 中国語や⽇本語⽂内でのソフト改⾏は、実際にはブラウザによって表⽰結果が異なる ○ Firefoxでは、スペースを⼊れずに⼆つの⾏を結合 ■ こちらはCSS Text Module仕様に従った挙動 ○ Blink/WebKit系では、スペースを⼊れて結合 コードスパンやHTMLタグ内でなく、2つ以上のスペースまたはバックスラッシュで先⾏さ れていない通常の改⾏は、ソフト改⾏としてパースされる。(ソフト改⾏はHTMLで改⾏ま たはスペースとしてレンダリングされうる(※may)。ブラウザ上での結果は同じである。)

Slide 28

Slide 28 text

ルビ() Issue: Proper ruby text () syntax support in Markdown ● ルビ(ふりがなのような本⽂に付属する⽂字)の記⼊をCommonMarkで仕 様化しようという提案 ○ furigana_markdown: [図](-と)[書](-しょ)[館](-かん)
 ○ parsedown_rubytext: [図書館]^(としょかん)
 ● Status: Open ● 現状の対応策 ○ ⽣HTMLの を書く ○ extensionを利⽤する

Slide 29

Slide 29 text

まとめ ● 強調表⽰(**)に失敗することがあるのは、CommonMarkの仕様に由来 ● Markdownはプレーンテキストメールの慣習にインスパイアされた⽂法に なっている ○ **強調表⽰の*ネスト*を許容** ● CommonMarkは、オリジナルのマークダウンとの互換性を重視しつつ、仕様 の曖昧さを排除しようとしている ○ 強調表⽰のパースを、スペースによる分かち書きがあることを前提として仕様化 ● ⽇本語には分かち書きがないため、強調表⽰に失敗してしまう ● ソフト改⾏やルビといったCJKと関連が深い話題についても、現在議論中

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

CommonMarkはいつv1.0になるのか? ● 実際、もうv1.0で良くない?と⾔う議論はある: Issue ○ ⼤きな仕様変更は⻑らくない ○ 外から不要に不確実性だと思われる可能性を除ける ● @jgm (John MacFarlane⽒)の反応 ○ “当初、1.0前に解決すべきと⾒ていた課題が未解決ではある” ■ Ambiguity in block quote definition など ■ 未解決の問題がこれほど⻑く残っているなら、それは重要じゃないのでは?と反論も ○ “1.0と呼ぶこと⾃体には前向きだが、それで何かが⼤きく変わるとは思わない” ○ CJKにおける強調の問題も重要視 ■ “世界⼈⼝の4分の1にとってより有⽤なものとなるよう、強調構⽂解析規則を修正する ことが望ましいでしょう” ■ “もちろん、これらの問題を 1.0 では解決せずに残し、後で対処することもできます。”