在“在另一个新命令中定义一个带有变量名的新命令”我们学习了如何\newcommand
在命令定义中使用另一个命令\newcommand
,当内部命令的名称需要包含外部命令的参数时。现在,假设我想做同样的事情,但内部命令\newcommand
也需要参数,即我希望以下代码能够工作:
\newcommand{\defsilly}[1]{%
% define a command named silly#1 , taking a single parameter
}
\defsilly{willy}
\sillywilly{theparameter}
动机:我正在编写一个论文文档类,其中包含一堆以下类型的命令对:
\newcommand{\iitthesis@authorEnglish}{Name of Author}
\newcommand{\authorEnglish}[1]{\renewcommand{\iitthesis@authorEnglish}{#1}}
我想用类似以下内容替换其中的每一对:
\iitthesis@thesisdatafield{authorEnglish}{Name of Author}
这定义了上述两个命令。
答案1
\newcommand{\iitthesis@thesisdatafield}[2]{%
\@namedef{iitthesis@#1}{#2}}
和
\iitthesis@thesisdatafield{authorEnglish}{Name of Author}
您将定义\iitthesis@authorEnglish
扩展为“作者姓名”,也就是说,您将发布相当于
\def\iitthesis@authorEnglish{Name of Author}
这不会检查定义的命令是否之前未定义。如果您也想进行此检查,请执行
\newcommand{\iitthesis@thesisdatafield}[2]{%
\expandafter\@ifdefinable\csname iitthesis@#1\endcsname
{\@namedef{iitthesis@#1}{#2}}}
但对于内部命令来说,通常不会这样做。
根据您的动机,我认为没有必要使用参数定义新命令。如果您还需要定义用户级命令,则可以使用相同的技术:
\newcommand{\iitthesis@thesisdatafield}[1]{%
\long\@namedef{#1}##1{\@namedef{iitthesis@#1}{##1}}}
在这种情况下说
\iitthesis@thesisdatafield{authorEnglish}
将定义命令\authorEnglish
,以便如果用户输入
\authorEnglish{A. U. Thor}
效果就像
\def\iitthesis@authorEnglish{A. U. Thor}
\long
导致要执行的前缀\@namedef
,因此\long\def
参数可以跨越一个或多个段落。
LaTeX 内核采用了这种技术,实际上\author{A. U. Thor}
定义了\@author
最终扩展为“AU Thor”。
答案2
与另一个问题一样,您需要使用\csname .. \endcsname
来构建宏名称,并将\expandafter
其扩展为该名称,然后才能使用\newcommand
(或类似方式) 定义该宏。只需在 后附加可选参数参数即可\endcsname
。
\newcommand{\iitthesis@thesisdatafield}[2]{%
\expandafter\newcommand\csname iitthesis@#1\endcsname{#2}%
\expandafter\newcommand\csname #1\endcsname[1]{\expandafter\renewcommand\csname iitthesis@#1\endcsname{##1}}%
}
请注意,您需要将#
内部宏中的参数加倍,以便清楚它不是外部宏的第一个参数。
有一个\@namedef{<name>}<parameter text>{<macro code>}
宏的作用基本相同,但使用的是 TeX 原语\def
,而不是 LaTeX 的\newcommand
。基本区别在于它不检查宏是否存在,而是在任何情况下都定义它,并且您必须以纯文本形式列出参数:#1
而不是[1]
,#1#2
而不是[2]
等等。