Pandocでの定理環境を考える

数学の文書をPandocで処理させる場合、定理等の記述をどうするか考える必要がある。LaTeXには定理環境があるが、 MarkdownやHTMLにはそういうマークアップは用意されていない。

ソースとしてはMarkdownかLaTeX、ターゲットとしてはHTMLかLaTeXを考える。

LaTeX

標準で定理環境(を定義するコマンド)がある。amsthmパッケージを読むと機能が拡張されたりproof環境が使えるようになったりする。

例:

\newtheorem{theorem}{定理}

\begin{theorem}[フェルマーの最終定理]
3以上の自然数 $n$ に対して、次を満たす整数 $x,y,z$ は存在しない:
\[x^n+y^n=z^n, xyz\ne 0\]
\end{theorem}
\begin{proof}
読者の演習問題とする。
\end{proof}

例の中では定理環境の名前を “theorem” としたが、実際の環境の名前は人によって違うだろう。

HTMLでの表現

LaTeXでの環境に相当するものとしては、divを使うのが自然だろう。

<div class="theorem">
</div>
<div class="proof">
</div>

「定理」や「証明」等の文字列を直接HTMLで書くか、CSSのcontent属性等を使って生成するかは、検討の余地がある。

Markdownでの表現

Markdown中でもHTMLタグを使えるので、HTMLと同様に書いても良い。

Pandocで処理させる場合は、Pandoc拡張でdivやspanをおしゃれに書ける。(他のMarkdownプロセッサーは知らない)

fenced_divs:

::: {.theorem}
:::

bracketed_spans:

[foo]{.bar}

これらを駆使して自分だけの定理記法を作ろう!(そして自分だけのPandoc filterを書く羽目になる)

ちなみに、筆者の「週刊 代数的実数を作る」のソース(Markdown)では

<div class="theorem">
**定理**(フェルマーの最終定理).
うんたらかんたら
</div>

という形式で定理を書いていた(Pandoc filterなしでHTML出力してもそれなりの見た目になるようにするため)が、いざこれを解釈するPandoc filterを書こうとすると定理名の部分(例だと「フェルマーの最終定理」)の解釈が無駄に面倒になってしまった。せめて

<div class="theorem">
**定理**([フェルマーの最終定理]{.thmname}).
うんたらかんたら
</div>

という風に定理名の部分が要素となるようにしておくべきだった。

Pandoc filterを書く

Pandoc本体には定理環境を処理する機能はないので、定理環境の処理にはPandoc filterを使う必要がある。定理環境用の既存のfilterはいくつか公開されているが、既存の書き方では満足できない場合、Pandoc filterを自作する必要がある。

Pandocをガチで使うなら、Pandoc filterを書ける能力は必須である。

Pandoc本体はHaskellで書かれているが、Pandoc filterは外部コマンドとして起動されるので、好きな言語でPandoc filterを書くことができる。Pandoc filterを書くのにオススメな言語を3つ挙げる:

  • Haskell: Pandoc自体にHaskellでPandoc filterを書くことを支援する関数が用意されている。
  • Python: Pandoc filterを書くためのライブラリーがあるらしい。
  • Lua: 最近のPandocではLuaで書かれたfilterを直接実行できるようになった。つまり、外部プロセス起動やJSON変換のコストが省ける。今後、簡単なフィルターはLuaで書くべきだろう。

筆者はこの記事に書いた定理環境以外にも、青空文庫形式のルビ(例:猫《ねこ》である)をHTMLや日本語LaTeXのルビに変換するフィルターをHaskellで書いて使っている。(この書き方ではルビの部分とその他の部分がPandocのAST上で区別されないので、パターンマッチや正規表現等で頑張って文字列処理をする必要がある。筆者はこのフィルターをLuaに移植しようと思ったが標準のstring.match等の文字列パターン機能が貧弱だったので断念した。)

Markdown→LaTeX

原稿をMarkdownで書いてLaTeX文書を得たい場合。

divタグを定理環境に変換することになる。

divタグをLaTeXの環境にするフィルターはすでにいくつか存在する:

出力に \begin{..} や \end{..} を挿入する際はPandoc ASTのRawBlockやRawInlineを使うことになる。

例に挙げたpandoc-latex-environment等は [RawBlock(“latex”, “\\begin{…}”] + content + [RawBlock(“latex”,”\\end{…}”)] という風に \begin{..} \end{..} を挿入しているが、proof環境でこれをやると出力されるLaTeXソース中で \end{proof} の前に1行空くため、「証明終わり」の記号の位置が変になる。

これを解決するには、 \end{proof} をブロックとして挿入するのではなく、証明の内容の最後の段落の末尾に RawInline(“latex”,”\\end{proof}”) を挿入するようにする。プログラムが複雑になるが、Haskellの強力なパターンマッチと高階関数を使えば割とさくっと書ける。Haskellを書こう。

LaTeX→HTML

原稿をLaTeXで書いて最終的にHTMLを出力したい場合。

この場合はLaTeXの定理環境をdivタグに変換することになる。

@mr_konn 氏が pandoc-japanese-filters でそういうfilterを書いているので、参考にすると良いだろう:https://github.com/konn/pandoc-japanese-filters/blob/master/env-to-div-filter.hs

関連スライド:(数式の入った)本をつくる, 2015年3月

筆者自身はLaTeXで書いた定理環境を含む文書をPandocで真面目に処理させた経験はないので、突っ込んだノウハウは持ち合わせていない。


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です