如何使一系列相关的可选参数宏可靠

如何使一系列相关的可选参数宏可靠

我使用一些有效但不可靠的\def魔法来减少与数学指标有关的样板。(这是在 LaTeX 中,但我想不出使用它的方法newcommand)。

\makeatletter
\def\@subarg[#1]{_{\rm #1}}

\def\Lam{{\Lambda}\@ifnextchar[\@subarg{}}
\def\Reg{{\cal R}\@ifnextchar[\@subarg{}}
% .
% .
% many similar definitions
% .
% .

\makeatother

这个想法是,当我说 时\Lam[frog]\@subarg@宏会吞噬可选参数并将其放入罗马字母中。如果我不想要罗马字母下标,我仍然可以像往常一样执行\Lam\Lam_k

所有这些都能正常工作,但不太可靠。很抱歉,我无法很好地描述错误,但我知道章节标题存在问题。

\subsubsection{Start $\Lam[fee] fi$ fo }
\subsubsection{Start $\Lam[fee] fi$ }
\subsubsection{Start $\Lam[fee]$ }

全部生成! Missing \endcsname inserted.

虽然

\subsubsection{Start $\Lam$ }
\subsubsection{Start $\Lam$} 

产生:! Argument of \@sect has an extra }.

有人知道如何让宏更加健壮吗?

答案1

您面临的问题之所以会逐渐出现,是因为您将内容插入到了一个脆弱的宏(一个分段单元)中。这个分段单元不仅发送要设置的内容,还会发送 ToC,这就是您遇到问题的地方。

解决这个问题的一种方法是,\protect在分段单元中使用宏时实际使用它们(例如,\protect\Lam...)。或者,你会问“如何使它们更强大?”好吧,使用\DeclareRobustCommand

在此处输入图片描述

\documentclass{article}
\makeatletter
\def\@subarg[#1]{_{\mathrm{#1}}}

\DeclareRobustCommand\Lam{\Lambda\@ifnextchar[\@subarg{}}
\DeclareRobustCommand\Reg{\mathcal{R}\@ifnextchar[\@subarg{}}
\makeatother
\begin{document}

\section{Start $\Lam[fee] fi$ fo}
\section{Start $\Lam[fee] fi$}
\section{Start $\Lam[fee]$}
\end{document}

答案2

\@ifnextchar当有更高级别的工具可用时,您应该避免使用;对于您的情况,我会使用\newcommand

\newcommand{\Lam}[1][]{%
  \Lambda
  \if\relax\detokenize{#1}\relax % test if the optional argument is empty
    % do nothing
  \else
    _\textnormal{#1}
  \fi
}

这不会引发您正在实验的脆弱性问题,因为具有定义的可选参数的命令\newcommand是强大的。

当然,输入多段类似的代码很烦人,甚至是错误的。所以我们可以定义一个 catch all 宏:

\documentclass{article}
\usepackage{amsmath}
\newcommand{\definevariable}[2]{% #1 = macro, #2 = actual variable
  \newcommand{#1}{#2\definevariabletestargument}%
}
\newcommand\definevariabletestargument[1][]{%
  \if\relax\detokenize{#1}\relax % test if the optional argument is empty
    % do nothing
  \else
    _\textnormal{#1}%
  \fi
}

\definevariable{\Lam}{\Lambda}
\definevariable{\Reg}{\mathcal{R}}

\begin{document}

\section{Here we have $\Reg$}

\subsection{With subscript $\Reg[xy]$}

\subsection{And $\Lam$}

\subsection{With subscript $\Lam[fee]$}

\end{document}

请注意使用\textnormal而不是\mathrm,例如,它允许在输入中留有空格。

一个更强大的工具是xparse

\documentclass{article}
\usepackage{amsmath,xparse}

\NewDocumentCommand{\definevariable}{mm}{% #1 = macro, #2 = actual variable
  \NewDocumentCommand{#1}{o}{%
    #2%
    \IfValueT{##1}{_\textnormal{##1}}%
  }%
}

\definevariable{\Lam}{\Lambda}
\definevariable{\Reg}{\mathcal{R}}

\begin{document}

\section{Here we have $\Reg$}

\subsection{With subscript $\Reg[xy]$}

\subsection{And $\Lam$}

\subsection{With subscript $\Lam[fee]$}

\end{document}

在此处输入图片描述

相关内容