段落を含む引数を取るマクロはどのように記述しますか?

段落を含む引数を取るマクロはどのように記述しますか?

段落を含む引数を取るマクロを書こうとしています。通常のマクロを書いて、その引数の 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 コマンド ( \defLaTeX ドキュメントでは使用しないでください) を使用すると、デフォルトで\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\oldparwhich を展開すると、which が生成され、\parwhich を展開すると、\oldparwhich が生成され、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プレフィックスなしで が使用されます。

関連情報