我想创建一个命令,明确要求用户在花括号中提供参数,否则会引发错误。
例如,采用以下命令定义:
\newcommand{\example}[1]{The argument is: "#1"}
现在,假设用户按以下方式使用它:
\example{Hello}
...将导致:
The argument is: "Hello"
但是,如果用户像这样使用它:
\example Hello
...将导致:
The argument is: "H"ello
对于我想要定义的命令来说,这种行为是不可取的——如何才能强制执行并向用户返回错误?我尝试使用ifthen
构造来测试参数,但实际上单个字母可能是一个有效的参数。\newcommand*
只有当命令后有空格时,使用才有效,如果在句子中间使用则无效。
答案1
您可以“将#
其作为宏参数抓取”(参见以 # 作为最后一个参数的宏和“抓取 #{” 宏参数(供解释)
\documentclass[11pt]{article}
\newcommand*{\example}{}% test if undefined; better safe than sorry
\def\example#{\exampleaux}
\newcommand{\exampleaux}[1]{The argument is: "#1"}
\begin{document}
\example{Hello}
\example Hello
\end{document}
第二次使用将出现错误
! Use of \example doesn't match its definition.
l.11 \example H
ello
答案2
在下面的例子中,宏\example␣␣
和\fetchbracedarg
形成一个循环,用于在令牌寄存器中累积括号嵌套的参数,\toks@
其数量对应于计数寄存器的初始值\@tempcnta
——我建议使用令牌寄存器而不是临时宏,以避免连续哈希值的数量减半(##
→ #
),这种情况发生在发生在⟨定义文本⟩在扩展相关宏时,宏的 s。
\documentclass{article}
\makeatletter
\newcommand\example{%
\toks@\expandafter{%
\expandafter\toks@
\expandafter{\the\expandafter\toks@\expandafter}%
\expandafter\@tempcnta\expandafter=\the\@tempcnta\relax
\innerexample
}%
\@tempcnta=3 %
\csname example\@firstofone{ } \endcsname
}%
\expandafter\@ifdefinable\csname example\@firstofone{ } \endcsname{%
\@namedef{example\@firstofone{ } }#{\fetchbracedarg}%
}%
\newcommand\fetchbracedarg[1]{%
\toks@\expandafter{\the\toks@{#1}}%
\advance\@tempcnta -1 %
\ifnum\@tempcnta=0 \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{\the\toks@}{\csname example\@firstofone{ } \endcsname}%
}%
\newcommand\innerexample[3]{%
\par This is argument 1: "#1"%
\par This is argument 2: "#2"%
\par This is argument 3: "#3"%
}%
\makeatother
\begin{document}
\example{A}{B}{C}
% \example{A}{B}C % Triggers error: ! Use of \example doesn't match its definition.
% \example{A}B{C} % Triggers error: ! Use of \example doesn't match its definition.
% \example A{B}{C} % Triggers error: ! Use of \example doesn't match its definition.
\end{document}