Edited at

完全攻略! LaTeX のマクロ定義


これは「TeX/LaTeX Advent Caleandar 2013」の 1 日目の記事です。

(2 日目は k16shikano さん です。)



長い前置き

TL;DR

マークアップ言語としての LaTeX の強みの一つとして「マクロが使える」ことがあります。すなわち、「自分流のマークアップ」を新たに作って、その実現(表現)方法を既存の命令の組み合わせとして定義できる、ということです。

たとえば、論文などで、新出の語句をその英訳とともに次のような書式で出力したいとします。

\textsf{参照透過性}(\emph{referential transparency})

Fig.1

ここで、次のようなマクロを作っておきます。

\newcommand*{\myTerm}[2]{\textsf{#1}{(\emph{#2})}}

すると最初の例は次のように表されます。

\myTerm{参照透過性}{referential transparency}

これで「新出語句の出力」という機能を、\myTermという命令(マークアップ)で表せたことになります。このようにマクロを作っておくと、後で「新出語句の出力」の書式が変えたい(例えば英訳のフォントサイズを小さくしたい、等)場合でも、この\myTermという命令の定義内容だけを変えれば済むことになります。

このように、マクロ作成は非常に便利で重要な機能ですが、残念ながら、LaTeX の初級者の間では「LaTeX のマクロは難しい」と思い込んでいる人が多いようにみえます。実のところ、現在入手可能な参考書の多くは「LaTeX のマクロ」を扱ってませんし、また解説のある参考書の多くでは、それが「TeX 言語の解説(特に TeX でのマクロ定義)」と同じ個所に載せられています。このため、「LaTeX のマクロ機能」が「TeX 言語の知識」と同じくらい難解な上級者向けの機能と思われがちなのかも知れません。

しかし、実際には、「LaTeX のマクロ作成」は何も難しくありません。特に、TeX 言語の知識は全く必要ありません。この記事を読めば(LaTeX 標準の範囲の)マクロ機能は完全にマスターできるので、マクロをどんどん活用しましょう!


基本編

さて、これまで「マクロ」と言ってきましたが、厳密には、LaTeX の用語に「マクロ(macro)」というものは存在せず、「LaTeX のマクロ」は正式には「ユーザ定義命令(user-defined command)」と呼ばれます1。なのでここからは「マクロ」でなく「(ユーザ定義)命令」と呼ぶことにします。

ユーザ定義命令を定義するには\newcommandという命令を使用します。


引数無しの命令

\newcommand{\命令名}{定義本体}

ここで\命令名は定義したい命令の名前で、LaTeX の通常の「命令の名前の規則2」に合ったもので、まだ意味が定義されていないものを指定します。(指定した命令が既に定義されていた場合はエラーになります。)この文の実行以降では、「\命令名を実行する」ことは「定義本体」を実行することと等価になります。

例を示します3

% \myAre: 赤い大きな文字で"アレ"と出力する.

\newcommand{\myAre}{{\color{red}\Large アレ}}
%※ \color はcolorパッケージの命令.

この定義文を実行した以降で、例えば

{\TeX}\myAre です。

のように記述すると、それは

{\TeX}{\color{red}\Large アレ}です。

Fig.2

という記述と等価になるわけです。ここで注意ですが、もし\myAreの定義を

% \myAre: 赤い大きな文字で"アレ"と出力する.

\newcommand{\myAre}{\color{red}\Large アレ}

のようにしてしまう(つまり「定義本体」部分には外側の{ }がない)と、{\TeX}は\myAre です。

{\TeX}\color{red}\Large アレです。

Fig.3

と等価になってしまい、これでは「です。」の部分(およびそれ以降の文章全体)にも色とフォントの変更が及んでしまいます。


引数付きの命令

\newcommand{\命令名}[引数の個数n]{定義本体}

ここで「引数の個数n」には 1~9 の整数を指定します。この文を実行した後は、\命令名{引数1}{引数2}...{引数n}という命令実行が「定義本体の中の、#1引数1に、……、#n引数nに置換したテキスト」の実行と等価になります。例えば、

% \myAlertA{テキスト} : 赤い大きな文字で出力する.

\newcommand{\myAlertA}[1]{{\color{red}\Large #1}}

と定義すると、命令\myAlertAの解釈は以下のようになります。



  • \myAlertA{アレ}{\color{red}\Large アレ}


  • \myAlertA{}{\color{red}\Large }

色の指定を可変にした命令を作ることもできます。

% \myAlertB{色名}{テキスト} : 指定の色を用いて大きな文字で出力する.

\newcommand{\myAlertB}[2]{{\color{#1}\Large #2}}



  • \myAlertB{red}{アレ}{\color{red}\Large アレ}


  • \myAlertB{blue}{コレ}{\color{blue}\Large コレ}


オプション引数付きの命令

オプション引数」というのは省略してもよい引数のことで、LaTeX の文法では、通常の(必須の)引数を{ }で囲うのに対し、オプション引数は[ ]で囲うという規則になっています。実は、さっき出てきた\newcommand{\myAlert}[1]{...}[1]もオプション引数です。

標準 LaTeX でのオプション引数付きのユーザ定義命令のサポートは限定的で、「最初の引数しかオプションにできない」という制限があります。

\newcommand{\命令名}[引数の個数n][引数1既定値]{定義本体}

この文を実行すると、\命令名[引数1]{引数2}...{引数n}という命令実行(引数1[ ]囲みであることに注意)は先と同様に「定義本体の中の、#1引数1に、……、#n引数nに置換したテキスト」の実行と等価になります。ところが、引数 1 はオプション引数なので省略することが可能で、もし省略して\命令名{引数2}...{引数n}の形で実行した場合、定義本体の#1は命令定義時に指定された引数1既定値で置換されることになります。

例として、先に出てきた\myAlertBで色名をオプション引数(既定値red)にしてみます。

% \myAlertC[色名]{テキスト} : 指定の色(既定値はred)を用いて大きな文字で出力する.

\newcommand{\myAlertC}[2][red]{{\color{#1}\Large #2}}

この命令\myAlertCの解釈は以下のようになります。



  • \myAlertC[blue]{コレ}{\color{blue}\Large コレ} (オプション引数指定)


  • \myAlertC{コレ}{\color{red}\Large コレ} (オプション引数省略、既定値redが使われる)


  • \myAlertC[]{コレ}{\color{}\Large コレ} (空テキストは有効な引数となる4


発展編


引数が段落をまたぐのを禁止する

命令を定義する際に、\newcommand命令の代わりに\newcommand*命令を用いると、定義される命令の(全ての)引数の中に改段落5を含めることが禁止されます。これは一種のフールプルーフ(誤り予防の策)として機能します。例えば、先に示した\myAlertCを使う時に、誤って引数の終わりの}を書き忘れたとします。

{\TeX}\myAlertC{アレです。

しかも{\TeX}\<(略

このソース(を含む文書)をコンパイルすると、LaTeX は\myAlertC{{に対応する}を見つけようとしてソースファイルを(恐らく)最後まで読んでいって、そこで初めてエラー6を出します。ここでもし、次のように、\myAlertC\newcommand*命令で定義していたとします。

\newcommand*{\myAlertC}[2][red]{{\color{#1}\Large #2}}

この場合は、先に示した間違ったソースをコンパイルすると、LaTeX は「アレです。」の後で改段落されているのを見つけた時点でエラーを出してくれます。なぜなら\myAlertCの引数に改段落を含むことは禁止されているからです。

もちろん、定義する命令によっては、引数に改段落を含むことが正当な場合もあります。例えば、次に示す命令\framedParBoxは、引数のテキストを一定の行幅で出力しさらに周りに枠を付けるものです。

% \framedParBox[幅]{テキスト} : テキストを指定の行幅で組み枠を付けて出力する.

\newcommand{\framedParBox}[2][10zw]{%
\fbox{\parbox{#1}{#2}}%
}

この命令は次のように段落をまたいで使用される可能性があるので、\newcommand*ではなく\newcommandを用いて定義すべきです。

\framedParBox{%

{\TeX}はアレです。

しかしWordはもっとアレです。
}

Fig.4


既存の命令の定義を変更する

\newcommand命令で新しい命令を定義しようとした時、指定した名前の命令が既に定義されていた場合はエラーになります。これは、「うかつに既存の命令の定義を変更してしまい、そのせいで後で意味不明な動作が発生する」状況を防ぐための安全装置です。

【余談】 TeX 言語(LaTeX でなくて)では\defという命令でマクロを定義しますが、これは指定した命令名が定義済であっても黙って上書きするという恐ろしい性質を持ちます。ドヤ顔で TeX の\def\letを使って、その結果 LaTeX を壊してしまって後で酷い目に合ったという話は時折聞きます。「TeX の機能を使うと偉い」なんてことは全くないので、素直に\newcommandを使いましょう。

しかし、「命令の定義が変更されることの影響」を完全に把握している状況では、定義を変更することが意味を持つでしょう。命令の定義を変更するには\renewcommand命令を用います7。この命令の書式は\newcommandと全く同じで、また*付きの\renewcommand*命令も存在します。

\renewcommand{\命令名}[引数の個数n][引数1既定値]{定義本体}

\renewcommand*{\命令名}[引数の個数n][引数1既定値]{定義本体}

この命令が使われる典型的な例は「自分で(\newcommandで)定義した命令の定義を変える」という場合です。その他に、LaTeX やパッケージについて、設定変更を\renewcommandで行うことが仕様として定められている場合があります。以下に例を示します。



  • \renewcommand{\abstractname}{ABSTRACT} ー 概要(abstract 環境)の見出しを変更する


  • \renewcommand{\topfraction}{.9} ー ページ上部へフロート(浮動体)を入りやすくする


  • \renewcommand{\theenumi}{(\arabic{enumi})} ー 番号付箇条書き(enumerate 環境)の項目ラベルの体裁を変える

LaTeX の範囲内では、\renewcommandを使えるのは以上のようなケースに限られます。何れにしても、「それで何が起こるのか」を知っていることが大前提です。


フォールバックの定義を与える

あまり LaTeX で使う機会はないのですが、「完全攻略」にするために書いておきます。

\providecommandは、指定した命令名が未定義のときだけ、指定された命令定義を行います。定義済だった場合は単に無視されます。

\providecommand{\命令名}[引数の個数n][引数1既定値]{定義本体}

\providecommand*{\命令名}[引数の個数n][引数1既定値]{定義本体}

「テンプレート」的な文書でパッケージの使用状況が変化しうる場合に、特定のパッケージで定義されるはずの命令のフォールバック定義を与えるのに使われることがあります。

\documentclass[a4paper]{jsarticle}

% color パッケージは \textcolor 命令を定義する
\usepackage[dvipdfmx]{color}
% color が"無い"時の \textcolor の定義
\providecommand*{\textcolor}[2]{#2}
\begin{document}
{\TeX}\textcolor{red}{アレ}です。
\end{document}

上掲の例では、color パッケージの使用を止めた場合に色指定の\textcolor命令が「単に無視される」ようにフォールバックの定義を行っています。


まとめ

「LaTeX のマクロ」は怖くありません! どんどん活用しましょう!





  1. 元々正式な用語でないので、LaTeX で何を「マクロ」と呼ぶかは人によって異なります。なお、TeX 言語には「マクロ(macro)」という用語が存在します。 



  2. LaTeX の命令は、「\の後に 1 字以上の英字の列」または「\の後に英字以外(数字も含む)の文字 1 つ」の何れかの形を持ちます。また、ユーザ定義命令については「\end~で始まる命令名は使えない」という追加の規則があります。 



  3. 以降に挙げる例では color パッケージが読み込まれていることを前提とします。 



  4. もちろん \color の引数は空にできないのでこの例では結局エラーが発生します。 



  5. LaTeX の文法では、改段落は「ソース上の空行」または「\par命令」により表されます。 



  6. ! File ended while scanning use of \myAlertC.というエラーが発生します。 



  7. \newcommand(*)とは逆に、\renewcommand(*)に指定する命令は既に意味が定義されている必要があります。未定義だった場合はエラー(! LaTeX Error: Command \XXX undefined.)になります。