![段落を含む引数を取るマクロはどのように記述しますか?](https://rvso.com/image/391694/%E6%AE%B5%E8%90%BD%E3%82%92%E5%90%AB%E3%82%80%E5%BC%95%E6%95%B0%E3%82%92%E5%8F%96%E3%82%8B%E3%83%9E%E3%82%AF%E3%83%AD%E3%81%AF%E3%81%A9%E3%81%AE%E3%82%88%E3%81%86%E3%81%AB%E8%A8%98%E8%BF%B0%E3%81%97%E3%81%BE%E3%81%99%E3%81%8B%3F.png)
段落を含む引数を取るマクロを書こうとしています。通常のマクロを書いて、その引数の 1 つに段落が含まれていると、マクロは機能しなくなります。
\documentclass{article}
\usepackage[utf8]{inputenc}
\title{test}
\begin{document}
\maketitle
\section{Introduction}
\def\mymacro#1{#1}
\mymacro{This
contains a paragraph}
\end{document}
これによりエラーが発生します:
Runaway argument? {This ! Paragraph ended before \mymacro was complete. <to be read again> \par l.15
\par
そこで、マクロの引数を拡張するために再定義しようとしましたが、コンパイルが停止しなくなりました。
\documentclass{article}
\usepackage[utf8]{inputenc}
\title{test}
\begin{document}
\maketitle
\section{Introduction}
\gdef\oldpar{\par}
\def\mymacro{\gdef\par{}\mymacroi}
\def\mymacroi#1{#1\gdef\par{\oldpar}}
\mymacro{foo
bar}
\end{document}
答え1
TeX が書かれた当時は、文書の 1 ページを処理するのに数分かかり、構文の強調表示はなかったので、 を忘れた場合にそれを検出する何らかのメカニズムがあったのは良いことでした}
。 は、デフォルトでは、であると明示的に指定しない限り、トークンを\def
許可しません。\par
\long\def
\def\mymacro#1{#1}
一方、LaTeX では、デフォルトで が使用されるため、適切な LaTeX コマンド ( \def
LaTeX ドキュメントでは使用しないでください) を使用すると、デフォルトで\newcommand
が作成されます\long\def
。「短い」 が必要な場合は\def
を使用します\newcommand*
。
xparse
デフォルトでは短い引数を返しますが、引数修飾子\long
を使用してマクロを定義することもできます+
。
\NewDocumentCommand\mymacro{ m}{#1}% \def
\NewDocumentCommand\mymacro{+m}{#1}% \long\def
2 回目の試みは巧妙で、2 つの点を除けばうまくいったはずです。
\gdef\oldpar{\par}
まず、 と を使用しています\gdef\par{\oldpar}
。拡大する \par
\oldpar
which を展開すると、which が生成され、\par
which を展開すると、\oldpar
which が生成され、which を展開すると\par
、which が生成され、… が生成されます。\oldpar
永遠に実行されます :/
この場合、\let
(またはグローバル効果を持たせるには)を使用する必要があります: 。これにより、 が何であるかに依存しないnamedの正確なコピーが作成されます。\global\let
\let\oldpar\par
\par
\oldpar
\par
2 番目に、暴走した引数のチェックは、 の定義とは独立した低レベルで実装されている\par
ため、同じエラーで失敗します。
\let\par\relax
\def\mymacro#1{#1}
\mymacro{foo
bar}
なぜなら、TeX が 2 つの\endlinechar
トークン (デフォルトではスペース) を検出すると、TeX は暗黙の\par
トークンを挿入し、Runaway argument
エラーが発生するからです。これを知っていれば、次のようになります。
\newcount\oldELchar
\oldELchar=\endlinechar
\def\mymacro{\endlinechar=-1\relax\mymacroi}
\def\mymacroi#1{#1\endlinechar=\oldELchar}
\mymacro{foo
bar}
エラーは発生しませんが、新しい行はスペースではなくなります。
答え2
で定義されたマクロの引数はトークン\def
を許可しません。また、空白行も許可しません。なぜなら、TeXがテキスト入力をトークンに変換する段階で、\par
空白行が に変換されるからです。この点で再定義は役に立たないことに注意してください。\par
\par
正確に\par
意味に関係なく、許可されないトークン。
解決策: マクロを作成します\long
。
\long\def\mymacro#1{#1}
より良い解決策:
\newcommand{\mymacro}[1]{#1}
\newcommand
内部的にが使用されるためです\long\def
。バリアント\newcommand*
では、代わりに\def
プレフィックスなしで が使用されます。