xparse(\NewDocumentCommand)

複数のオプション引数や、星付きの変種を備えた命令を作りたくなったら、\newcommand の引数の数え方では手に負えません。そこで使うのが、引数の「種類」を文字列で宣言する現代的なインタフェース \NewDocumentCommand です。もとは xparse パッケージの機能でしたが、いまは LaTeX カーネルの一部。引数指定のミニ言語と、与えられた引数を調べる判定命令まで、このページでひととおり扱います。

いまはカーネルの一部

かつては \usepackage{xparse} が必要でしたが、2020 年 10 月の LaTeX 以降、この仕組みは LaTeX カーネルに取り込まれました\NewDocumentCommand などの命令は最初から使え、xparse を読み込む必要はほとんどありません。カーネル内でこの機能を実装しているファイルは **ltcmd** と呼ばれ、xparse パッケージ自体は公式に「obsolete(用済み)」と位置づけられています。ごく一部の非推奨な引数型を除けば、新しいコードは xparse を読み込まずにそのまま書けます。

この現代的な定義法は、意味(インタフェース)と実装を切り離す 発想です。利用者から見た引数の並び(必須・オプション・星付き)を「引数指定(argument specification, arg-spec)」として宣言すると、本体のコードは #1#2 … という正規化された形で常に引数を受け取れます。\newcommand の基礎は「マクロの定義」のページで扱っているので、まだなら先に目を通しておくと差分が見えやすくなります。

命令と環境を定義する

基本の形は **\NewDocumentCommand{\cmd}{⟨arg-spec⟩}{⟨code⟩}** です。第 1 引数に作る命令名、第 2 引数に引数指定、第 3 引数に本体を書きます。\newcommand と同じく、目的の違う三つの仲間があり、違うのは「すでに定義済みの名前にどう振る舞うか」です。

命令既存の名前に対して
\NewDocumentCommandすでに定義済みならエラー
\RenewDocumentCommand未定義ならエラー(既存を作り直す)
\ProvideDocumentCommand未定義のときだけ定義する
\DeclareDocumentCommand常に上書きする(控えめに)

環境にも同じ仕組みがあり、**\NewDocumentEnvironment{⟨env⟩}{⟨arg-spec⟩}{⟨開始コード⟩}{⟨終了コード⟩}** で定義します(\Renew…\Provide…\Declare… も同様)。引数は \begin{⟨env⟩} のあとに与えられ、開始・終了どちらのコードからも参照できます。詳しくは「環境の自作」のページへ。なお、ここで作る命令はすべて自動的に 頑強(robust) になる(内部で ε-TeX の \protected 機構を使う)ため、見出しやキャプションでの \protect の心配が要りません。

もう一つ、**\NewExpandableDocumentCommand** という展開可能な版もあります。\edef\write の中など、命令が「展開」されてしまう文脈で使える代わりに、引数指定で使える型に制限があり(後述の st のような真偽判定や v などは使えません)、ふつうの文書作りでは通常版で十分です。

引数指定のミニ言語

引数指定は 1 文字ずつが 1 つの引数の「型」を表す文字列 です。必須引数か、オプションか、星か、特定の文字で区切られるか…を文字で並べていきます。各型は本体に #1#2 … として届きますが、与えられなかったオプション引数には特別な値が入る 点が肝心です。主要な型を次の表にまとめます。

書き方意味本体での受け取り
mm必須引数({}通常の #1
oo省略可能な [...]無ければ -NoValue-
OO{default}既定値つきオプション無ければ default
ss* の有無\BooleanTrue / \BooleanFalse
tt⟨char⟩指定文字トークンの有無\BooleanTrue / \BooleanFalse
rr⟨d1⟩⟨d2⟩d1d2 で囲む必須引数無ければエラー後 -NoValue-
dd⟨d1⟩⟨d2⟩d1d2 で囲むオプション無ければ -NoValue-
ee{⟨tokens⟩}装飾子(^_ など)各々、無ければ -NoValue-
vvベルバティム引数そのままの文字列

m** は最も基本の必須引数で、{...} でも 1 トークンでも受け取り、外側の {} は外されて本体に渡ります。**o** は標準的なオプション引数 [...]、**O{default}** はそれに既定値を与えた版です。OD のような 大文字の型は既定値を指定できod のような小文字版は代わりに特別な印 -NoValue- を返します。

s** は星 * の有無を見る型で、* があれば \BooleanTrue、無ければ \BooleanFalse が入ります。任意の 1 文字に一般化したのが **t⟨char⟩** で、たとえば t+ なら + の有無を真偽で受け取れます。**r⟨d1⟩⟨d2⟩** は自分で選んだ区切り文字(たとえば r() で丸括弧)で囲む「必須」の区切り引数で、開き側が無いとエラーを出して -NoValue- を補います。区切りはあるがオプション、というのが **d⟨d1⟩⟨d2⟩** です。

少し変わり種が **e{⟨tokens⟩}** で、^_ のような 装飾子(embellishments) をまとめて受け取ります。e{^_} とすれば ^{...}_{...} を任意の順で拾い、与えられなかったものは -NoValue- になります(指定するトークンはすべて相異なる必要があります)。**v** は \verb のように ベルバティム(そのまま) 引数を読み取る型です。なお区切り型(rd など)の区切りには TeX のグループ化に使う {} は使えないので、[]()"" のような自然に対になる文字を選ぶのが定石です。

引数を調べる:判定命令

オプション引数や星を扱うには、「与えられたかどうか」を本体の中で判定する必要があります。そのための専用命令が二系統あります。まず **\IfNoValueTF{#1}{⟨無い場合⟩}{⟨有る場合⟩}** は、引数が -NoValue-(=与えられなかった)かどうかを調べ、無ければ第 1 ブロック、有れば第 2 ブロックを実行します。逆向きの **\IfValueTF** もあり、T だけ・F だけの版(\IfNoValueT / \IfNoValueF\IfValueT / \IfValueF)も使えます。

st で受け取った真偽値には、専用の **\IfBooleanTF{#1}{⟨星あり⟩}{⟨星なし⟩}** を使います。#1\BooleanTrue なら第 1 ブロック、\BooleanFalse なら第 2 ブロックを実行します(\IfBooleanT / \IfBooleanF もあります)。**\IfNoValueTF 系は od などのオプション引数に、\IfBooleanTF 系は st の真偽引数に** —— 取り違えないのがコツです。なお -NoValue- は文字列の -NoValue- とは一致しないよう作られているため、\IfNoValueTF で必ず判定してください。

実例:星と既定値つきオプション

s O{} m という引数指定で、星付きの変種と既定値つきオプション引数の両方を持つ命令を作ってみます。ここでは見出しコマンドを例にします。#1 が星(\IfBooleanTF で判定)、#2 がオプションの短縮見出し(既定は空)、#3 が本見出しです。

latex
\NewDocumentCommand{\heading}{s O{} m}{%
  \IfBooleanTF{#1}%
    {\textbf{#3}}%                       星つき: 番号なしの見出し / starred: unnumbered
    {\section%
       \IfNoValueTF{#2}%
         {{#3}}%                          短縮見出しなし / no short title
         {[#2]{#3}}%                       短縮見出しあり / with short title
    }%
}

% 使用例 / usage
\heading{Introduction}             % 通常の番号つき節
\heading[Intro]{A Long Introduction} % 目次用に短縮見出しを指定
\heading*{Preface}                 % 星つき: 太字の無番号見出し

ここで O{} の既定値を空にしているのは、\IfNoValueTF で「与えられたか」を判定したいからではない点に注意してください。実は o を使えば未指定時に -NoValue- が入るので、上のように \IfNoValueTF で分岐できます。一方 O{} のように既定値を与えると常に値が入る(未指定なら空)ため、その場合は \IfNoValueTF ではなく「中身が空かどうか」を \tl_if_blank:nTF(expl3)や \ifblank(etoolbox)で調べるのが定石です。上の例ではオプション引数を o(既定値なし)にすると意図どおりに動きます。

なぜ \newcommand より優れるのか

\newcommand のオプション引数は 先頭の 1 個だけ で、星付きの変種は標準では作れません。従来はそれを補うために \@ifstar\@ifnextchar といった低水準の仕掛けを手書きしていましたが、これらは \makeatletter が必要で、空白の扱いや入れ子で壊れやすく、可読性も高くありません。

  • オプション引数を複数、しかも独立に持てる(o o mO{a} O{b} m など)。
  • 星付きの変種を正式に扱える(s\IfBooleanTF)。\@ifstar のハックが不要。
  • 既定値が宣言的O{default} と書くだけで、未指定時の値が決まる。
  • 最初から頑強(robust)。見出し・キャプションでも \protect が要らない。
  • 区切り引数(rd)や装飾子(e)など、\newcommand では書けない入力構文も表現できる。

まとめると、ごく単純な短縮マクロなら \newcommand で十分ですが、**引数の構造が少しでも凝るなら \NewDocumentCommand が第一候補** です。さらに本体の処理をプログラムとして書き込みたくなったら、expl3(LaTeX3 プログラミング層)と組み合わせるのが自然な発展です。クラスやパッケージの作り方は「クラス・パッケージの作成」のページへ。