LaTeX においては、二重バックスラッシュ \\
コマンドで強制改行、または行列等の表記における行区切りを行う。その \\
コマンドには、いくつかの変種がある:
\\ \\[長さ] \\* \\*[長さ]
角かっこ [ ]
で囲ったものはオプション(省略可能)引数で、その改行における行間を指定する。スター *
がついたものは、改ページを抑制する。
コマンドの最後の引数がオプション引数になっているというのは曲者で、直後に通常の角かっこを書こうとした時に意図しない挙動になる可能性がある。
このような形でオプション引数を取るマクロとしては、代表的なものに \item
がある。箇条書きの内容が [ ]
から始まる場合は要注意、というのは、ある程度 LaTeX をやっている人なら知っているだろう:
\begin{enumerate} \item [1,2,3] \end{enumerate}
オプション引数として解釈されるのを抑制するには、典型的には {}
を挟んだり、 {}
で囲むという手段がある:
\item {} [1,2,3] \item {[1,2,3]}
ここまでは普通の LaTeX 解説書に載っている内容だと思う。
字句解析の規則
さて、 TeX の字句解析(トークン化)の規則では、コマンド名には3種類ある:
- バックスラッシュにアルファベット続き
- バックスラッシュにアルファベット以外(記号、空白)1文字
- 半角チルダ
~
または個別に特殊文字化されたもの(カテゴリーコード13)
1.の場合は、コマンド名直後の空白はトークン化の際に無視される。2.と3.の場合は、バックスラッシュの直後が空白の場合を除き、空白は無視されずに残る(TeX では基本的に1文字以上の空白文字の連なりは1文字の空白と等価であり、 \
の後の空白が無視されるのはその仕様の一部と考えられる)。
この規則により、 \item[x]
と \item [x]
はトークン列として等価だが、 \\[42pt]
と \\ [42pt]
はトークン列としては等価ではない。そのため、コマンドの実装によっては \\[42pt]
と \\ [42pt]
に違いが生まれる可能性がある。
普通は同じ名前のコマンドなら同じ実装だろうと思うかもしれないが、現実には \\
という名前のコマンドは環境等を使うたびに上書きされるので、場所によってコマンドの実装が異なる。
LaTeX 標準の \\
LaTeX2ε の標準的な挙動としては、コマンド名がアルファベットか記号1文字かに関わらず、コマンド名と(必須または省略可能)引数の間の空白、および引数同士の間の空白は無視される。最後の引数が省略可能な場合も同様である。
\\
も例外に漏れない。つまり、 \\
の後に空白を入れても改行を入れても、その後の [ ]
がオプション引数として解釈される。
次を含む文書を処理すると hoge と piyo の間にやたら隙間が空くし:
hoge \\ [42pt] piyo
次を含む文書はエラーとなる:
\[\begin{array}{rl} (a,b)&=\{x\mid a<x<b\}, \\ [a,b]&=\{x\mid a\le x\le b\} \end{array}\]
本文中の強制改行としての \\
の他に、 \\
が使える環境、コマンドには次がある:
- array
- eqnarray(*)
- tabular, tabbing
- \shortstack, \author
AMSmath における \\
AMSmath が提供する align 系の環境でも \\
で行を区切る。具体的には、以下の環境が該当する:
- align(*), aligned
- flalign(*)
- alignat(*), alignedat
- gather(*), gathered
- multline(*)
- split
- cases
- (p,b,B,v,V)matrix, matrix, smallmatrix
- CD
AMSmath の実装では、 \\
の直後に空白(または改行)を入れると、その後の [
がオプション引数として認識されない。
\begin{align*} (a,b)&=\{x\mid a<x<b\}, \\ [a,b]&=\{x\mid a\le x\le b\} \end{align*}
ソースコードを読むと、わざわざ LaTeX の内部コマンド \@ifnextchar
ではなく独自に \new@ifnextchar
を定義して使っており、(ドキュメントには見当たらないが)これは意図的な仕様であることがわかる。
(AMSmath の環境中における \\
の実体は \math@cr
であり、その定義については texdoc amsmath.pdf を参照。\new@ifnextchar
の定義は texdoc amsgen を参照)
Pandoc の場合
多くの Markdown 処理系では数式は特別扱いせず MathJax にマルナゲすることが多いと思うが[要出典]、 Pandoc は自前で LaTeX で書かれた数式を解釈している。
自前で数式を解釈することの利点として、 Markdown の文法と LaTeX の文法の干渉を回避できたり、MathJax 以外の選択肢として MathML への変換等が利用できたりするわけだが、同時に Pandoc が LaTeX の解釈を誤るかもしれないというリスクも抱え込むことになる(まあ Pandoc は OSS なので気づいたらその都度直していけば良い)。
さて、わざわざこの記事で取り上げていることから察せられるかもしれないが、現在の Pandoc は AMSmath の \\
を正しく実装していない。直後に空白があっても [ ]
をオプション引数として取り扱うようになっている。
このバグに遭遇した際の回避策は、 \\
と [ ]
の間に {}
を挟むことである。
一応 Pandoc (の一部である texmath)の方に Pull Request を出しておいたので、そのうち修正されるだろう(されるといいな)。 https://github.com/jgm/texmath/pull/105
MathJax と KaTeX の場合
Pandoc に気を取られて真面目にテストしていない(= Git リポジトリの最新版で試していない)が、 KaTeX も Pandoc と同様のバグを抱えているように見える。
その点、 MathJax は問題なさそうに見える。
余談:xparse の省略可能引数
「コマンドの最後の引数が省略可能である」という仕様ははっきり言って邪悪である。せめて、(AMSmath のように)空白が空いていたら引数として認識されないようにしてほしい。
これだけ普及した LaTeX の仕様を今更変更するわけにはいかないが、これから作られるコマンドの仕様を望ましいものにすることはできる。
xparse パッケージで提供されている \NewDocumentCommand
系のコマンドでは、最後の引数が省略可能な場合は、その直前の引数と引数開始の [
の間に空白が入ってはならないという仕様になっている。
\documentclass{article} \usepackage{xparse} \RenewDocumentCommand\${o}{Foo} \begin{document} \$[x] \$x \$ [y] \$ x \end{document}
これの出力は Foo Foox Foo [y] Foo x となり、1番目の \$
の直後の [x]
はオプション引数として認識されるが、3番目の \$
の後の [y]
はオプション引数として認識されていないことがわかる。
(LaTeX2ε 流に \renewcommand\$[1][x]{Foo}
と定義した場合と比較してみよう!)
日本語で xparse の概略を知りたいという人は
xparse パッケージでスゴイ LaTeX マクロを作ろう! – Qiita
を参照すると良さそうである。