Closed akabekobeko closed 3 years ago
<body data-math-typeset>
が出力されますが、これは次のようにしないとVivliostyleは数式有効にしてくれません。
<body data-math-typeset="true">
@MurakamiShinyu
ありがとうございます。真偽値から文字列に修正して data-math-typeset="true"
となるようにしました。
数式が複数行で書かれているときの処理に疑問があります。
まず、$$
... $$
のあいだにLaTeX形式の1行だけの場合
$ lib/cli.js --math
$$
\LaTeX \\ \LaTeX
$$
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.9/MathJax.js?config=TeX-MML-AM_CHTML"></script>
</head>
<body data-math-typeset="true">
<p>
$$
\LaTeX \\ \LaTeX
$$
</p>
</body>
</html>
\\
がそのまま出力されていて問題ありません。
しかし、$$
... $$
のあいだに2行書いた次の場合
$ lib/cli.js --math
$$
\LaTeX
\LaTeX \\ \LaTeX
$$
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.9/MathJax.js?config=TeX-MML-AM_CHTML"></script>
</head>
<body data-math-typeset="true">
<p>
$$
\LaTeX
\LaTeX \ \LaTeX
$$
</p>
</body>
</html>
\\
がMarkdownのエスケープの処理がされて \
になってます。LaTeX数式扱いにならないようです。
@MurakamiShinyu
以上を踏まえて
のどちらにするのがよいでしょうか?
単一パラグラフ想定 のみ実装でよいと思います。つまり、複数行にわたっていても、空白行(連続した改行)がない場合は単一パラグラフです。
pandoc での数式の扱いを調べたところ、そのようになっているのが分かりました。
そのうえpandocでは、インライン数式 $
... $
は、はじめの $
のあとは空白や数字ではないこと、おわりの $
のまえは空白でないこと、おわりの $
のあとが数字でないことという制限があり、それにより $
が意図せず数式記法として扱われてしまうのを防ぐようになっていることが分かりました。
詳しくは pandoc のマニュアル→ https://pandoc.org/MANUAL.html#math
pandoc --mathjax
を試すと、
$ pandoc --mathjax
Text $foo bar$ text
^D
<p>Text <span class="math inline">\(foo bar\)</span> text</p>
$ pandoc --mathjax
Text $50 text $100
^D
<p>Text $50 text $100</p>
↑ $
のあとが数字やスペースだと数式扱いにならない。
$ pandoc --mathjax
Text $$ \LaTeX
\LaTeX \\ LaTeX
\LaTeX $$ text.
^D
<p>Text <span class="math display">\[ \LaTeX
\LaTeX \\ LaTeX
\LaTeX \]</span> text.</p>
$ pandoc --mathjax
$$
foo
bar
$$
^D
<p>$$ foo</p>
<p>bar $$</p>
↑数式の途中に空白行は入れられない(数式扱いにならない)。
このpandocの数式の扱いの仕様は参考になるかと思います。
ありがとうございます。remark の inline 系でこの条件を満たせるかを調べてみます。
それとこれも追加ですね。
そのうえpandocでは、インライン数式 $ ... $ は、はじめの $ のあとは空白や数字ではないこと、おわりの $ のまえは空白でないこと、という制限があり、それにより $ が意図せず数式記法として扱われてしまうのを防ぐようになっていることが分かりました。
現在は $
または $$
開始をチェックしていますが、前者は $$
、後者は $$$...N
のみを回避するようにしています。よって $1 + 1 = 2$
を通しているのですが、数字と空白の否定を正規表現へ追加します。
すみません、
pandocでは、インライン数式
$
...$
は、はじめの$
のあとは空白や数字ではないこと、おわりの$
のまえは空白でないことという制限があり、
と書いたのですが、間違ってたので、次のように直しました:
pandocでは、インライン数式
$
...$
は、はじめの$
のあとは空白ではないこと、おわりの$
のまえは空白でないこと、おわりの$
のあとが数字でないことという制限があり、
https://pandoc.org/MANUAL.html#math をよく読むと "and must not be followed immediately by a digit." というのは、$
...$
の直後に数字がこないことということなので、はじめの $
ではなくておわりの $
です。
これによって、 $1 + 1 = 2$
はその直後が数字でないかぎりはインライン数式として扱われます。
$ pandoc --mathjax
$1 + 1 = 2$
<p><span class="math inline">\(1 + 1 = 2\)</span></p>
$ pandoc --mathjax
$1 + 1 = 2$100
<p>$1 + 1 = 2$100</p>
<span class="math inline">\(
...\)</span>
, <span class="math display">\[
...]</span>
というHTMLマークアップ出力も pandoc --mathjax
と互換にするのがよいかもしれません。MathJax はこれらのタグがなくても \(
...\)
, \[
...\]
, $$
...$$
を数式扱いにしますが、これらのタグがあると次のメリットがあります。
<span class="math inline">
や <span class="math display">
のところが数式だということが分かりやすいし、論理構造的にセマンティックなマークアップとなる。span.math.inline { ... }
や span.math.display { ... }
として数式にスタイルを指定することが可能。ありがとうございます。
と書いたのですが、間違ってたので、次のように直しました:
この仕様により $... is $50
みたいなものを数式の範囲としないようにしているのですね。箇条書きにしてみました。間違えていたらツッコミお願いします。
$
または $$
$
または $$
あわせて
<span class="math inline">\(
...\)</span>
,<span class="math display">\[
...]</span>
というHTMLマークアップ出力もpandoc --mathjax
と互換にするのがよいかもしれません。
も追加実装します。今回の対応で元の remark-prase 時代にあった HTML 出力が廃止されたので対応する CSS セレクターをドキュメントから削除したのですが、この元処理は村上さんの書かれているとおり明示的なスタイル付けを動機としているのだと思われます。そして数式の利用者にも需要はありそうなので新版でも↑の HTML 出力を実装してみます (ドキュメントにも CSS セレクターを改めて掲載します)。
箇条書きにしてみました。間違えていたらツッコミお願いします。
- 開始
$
または$$
- 直後は空白と数字以外
- 終端
$
または$$
- 直前は空白以外
- 直後は数字以外
インライン数式 $
...$
とディスプレイ数式 $$
...$$
で規則が違います。
インライン数式 $
...$
:
$
$
\$
($
の直前に \
が奇数個)は終端扱いしないディスプレイ数式 $$
...$$
:
$$
$$
(注)pandocのマニュアル https://pandoc.org/MANUAL.html#math では、途中に空白行がないかぎり複数行にわたってもよいというのはディスプレイ数式だけのように読めるのですが、試してみるとインライン数式でも同様なようです。
ありがとうございます。
(注)pandocのマニュアル https://pandoc.org/MANUAL.html#math では、途中に空白行がないかぎり複数行にわたってもよいというのはディスプレイ数式だけのように読めるのですが、試してみるとインライン数式でも同様なようです。
についてはインライン側も複数行で対応してみます。なお空白行がある場合、おそらくコード ブロックなどの特殊な構文をのぞき remark-parse (の CommonMark/GFM) によってパラグラフが分離されると思われます。念の為、これが除外されることのテストは実装します。
以下の正規表現でおおむね実現できた。
/\$([^($| )].*?[^($| )])\$(?!(\$|\d))/gs
/\$\$([^$].*?[^$])\$\$(?!\$)/gs
フラグ s
で .*?
を改行を含めて最短一致できるのと、remark の インライン tokenizer 仕様によるパラグラフ限定のあわせ技となる。display のほうはパラグラフ限定により s
フラグ追加だけでいける。
インラインの「\$
($
の直前に \
が奇数個)は終端扱いしない」が課題。
/\$([^($| )].*?[^(\\|$| )])\$(?!(\$|\d))/gs
でいけそうに思えるが $1 + 1 = 2$ $x=y$5 $x = \\$y$ $1 + 1 = 2$
のように終端として除外対象となる数値などがあった場合は $x=y$5
でトークン消費されないため $x=y$5 $x = \\$y$
がヒットする。$5
とスペースではじまる $x
が終端除外されて y$
に至るわけだ。
よって正規表現を変えるか tokenizer 側でなんとかする必要あり。
前述のコメントを見返して $1 + 1 = 2$ $x=y$5 $x = \\$y$ $1 + 1 = 2$
が
$1 + 1 = 2$
= \(1 + 1 = 2\)
$x=y$5 $x = \\$y$
= \(x=y$5 $x = \\$y\)
$1 + 1 = 2$
= \(1 + 1 = 2\)
になるのは正しい挙動に思える。2 を問題としていたが y$5
や \\$y
は数式中の $
といえるので、むしろ 2 を $x=y$5
と \($x = \\$y$\)
にしないほうがよさそうだ。この認識でよければ現時点のローカル実装で要件は満たせたかもしれない。
@MurakamiShinyu @yamasy1549 提案された内容をひととおり実装してみました。テスト コードとドキュメントのレビューをお願いします
気がついた問題:
$
のあとが (
や |
だと数式扱いにならない$ lib/cli.js --math --partial
$(1+2)$
^D
<p>$(1+2)$</p>
$ lib/cli.js --math --partial
$|a+b|$
^D
<p>$|a+b|$</p>
正規表現に問題があります。
const regexpInline = /\$([^($| )].*?[^(\\|$| )])\$(?!(\$|\d))/gs;
[^($| )]
では (
, $
, |
, `,
)` を除く文字ということになります。
$a$
が認識されないこの正規表現では2文字以上でないとマッチしません。
pandoc の場合では U+0020 SPACE 以外の空白文字も同様に扱われます。pandocでのテスト:
開始 $
の後や終了 $
の前がタブ U+0009 の場合も数式扱いしない
$ pandoc --mathjax
$ a+b $
<p>$ a+b $</p>
開始 $
の後や終了 $
の前が改行の場合も数式扱いしない
$ pandoc --mathjax
$
a+b
$
<p>$ a+b $</p>
この pandoc の動作にあわせるのがよいと思います。
\
のあとの $
でインライン数式が終了するべき$ lib/cli.js --math --partial
$a+b\\$
^D
<p>$a+b\$</p>
偶数個の \
でも $
をエスケープしてしまう。
pandocではそんなことはない:
$ pandoc --mathjax
$a+b\\$
<p><span class="math inline">\(a+b\\\)</span></p>
覚書。
以下を修正。
$
のあとが (
や |
だと数式扱いにならない否定 [^]
において ()
でグルーピングして区切りは |
だと勘違いしていたのが原因。ここへはそのまま対象文字を列挙するだけでよかった。空白はそれのみが仕様だと認識していたので意図的に文字 ` を指定していたが、改行やタブ文字も除外してよいとのことなのでメタ文字
\s` に変更。
残件。
$a$
が認識されない
.*?
で 0 文字以上だが開始直後と終了直前で「それぞれ 1 文字ずつ判定 = 合計 2 文字は必要」なのが原因と思われる\
のあとの $
でインライン数式が終了するべき
@MurakamiShinyu ありがとうございます!手元で試して OK でした。そのテスト コードとドキュメント修正を加えてコミットします。
@MurakamiShinyu テスト コードと村上さんによる修正を反映したドキュメントの変更をおこないました。これでよろしれけば merge します。
@yamasy1549
docs/vfm.md
の Math equation
をレビューお願いします。特に問題ないようであれば approve してください。
特に問題点の指摘もなさそうなので merge しました。利用してみて意見などがありましたら、改めて Issue などでご指摘ください。
@akabekobeko たいへん遅くなってすみません、今確認しました。ありがとうございます!
37 の議論を踏まえて MathJax 形式の数式構文を実装しました。
@MurakamiShinyu @yamasy1549 ドキュメント
docs/vfm.md
とテストtests/math.test.ts
のレビューをお願いします。補足として当初は unified のみに依存する独自処理を実装していたのですが、remark を利用するとこれが拡張する tokenizer/method として登録しないと Markdown 構文間の排他がおこなわれないため、VFM 1.0 時点では仕方なく remark プラグインとすることにしました。
VFM 2.0 で remark 13 未満のインターフェースを判定して分岐しているため 13 以降では独自処理に切り替わるはずです。ただし remark 13 でも構文の排他は remark (micromark) として実装しないと機能しないと予想しています。