我想做一些类似的事情这个问题 但正在尝试做一些更简单的事情。以下宏(我想将其归因于,但不记得我在哪里学到的)
\makeatletter
\def\myNorm#1{%
\def\tmp{#1}
\ifx\tmp\@empty%
{\rho}
\else%
{\rho(#1)}
\fi%
}
\makeatother
如果第二个参数不为空,则用括号括起来,例如,
$\myNorm{5}$
并$\myNorm{}$
返回 resp$\rho(5)$
和$\rho$
。
上面的结构有点拗口,而且很难记住,但我经常使用它。所以我想自动化宏创建过程。具体来说,我想要做的是创建一个宏创建宏,它看起来像
\MacroTemplate#1#2
因此第一个参数将是新宏的名称,例如,myNorm
而第二个参数将是,\rho
例如,这样
\MacroTemplate{myNorm}{\rho}
会构造我上面明确定义的宏。然后我可以继续编写$\myNorm{\rho}$
并$\myNorm{\rho}{5}$
返回上述内容。但我也可以定义
\MacroTemplate{yourNorm}{\nu}
和和写$\yourNorm{\nu}{5}$
和$\yourNorm{\nu}{}$
将分别返回$\beta(5)$
和$\beta$
而不必每次想要类似的东西时都记住复杂的构造。非常感谢您的任何建议。
答案1
你的定义是
\makeatletter
\def\myNorm#1{%
\def\tmp{#1}
\ifx\tmp\@empty%
{\rho}
\else%
{\rho(#1)}
\fi%
}
\makeatother
但它应该是
\makeatletter
\def\myNorm#1{%
\def\tmp{#1}%
\ifx\tmp\@empty
\rho
\else
\rho(#1)%
\fi
}
\makeatother
您不会得到虚假空格,因为您在数学模式下使用宏,而空格无论如何都会被忽略。“true”和“false”文本周围不需要括号:实际上,括号在不同情况下可能很危险。
我省略了%
控制序列结束行之后的部分,因为当 TeX 读取输入文件时,它们后面的空格(或行尾)都会被忽略。
首先要理清的是检查空参数,最好使用更高级别的宏来完成,例如 from etoolbox
,它提供\ifblank
:
\usepackage{etoolbox}
\newcommand{\myNorm}[1]{\rho\ifblank{#1}{}{(#1)}}
现在定义模板宏非常简单:
\newcommand\MacroTemplate[2]{%
\newcommand{#1}[1]{#2\ifblank{##1}{}{(##1)}}%
}
模板宏要定义的命令中的参数变成##1
。
因此你的\myNorm
宏可以定义为
\MacroTemplate{\myNorm}{\rho}
从概念上来说,使用如下语法会更好
\myNorm
\myNorm[5]
带有一个可选参数(但这需要更改所有文档):
\newcommand{\MacroTemplate}[2]{%
\newcommand{#1}[1][]{#2\ifblank{##1}{}{(##1)}}%
}
使用xparse
,第二种方法很简单,不需要etoolbox
:
\usepackage{xparse}
\NewDocumentCommand{\MacroTemplate}{mm}{%
\NewDocumentCommand{#1}{o}{#2\IfValueT{##1}{(##1)}}%
}
答案2
我想你会喜欢这样的想法:
\documentclass{article}
\usepackage{scrbase}% provides \IfArgIsEmpty
\newcommand*{\MacroTemplate}[2]{%
\newcommand*#1[1]{#2\IfArgIsEmpty{##1}{}{(##1)}}%
}
\MacroTemplate\myNorm\rho
\MacroTemplate\yourNorm\nu
\begin{document}
$\myNorm{5}$ vs. $\myNorm{}$ and $\yourNorm{5}$ vs. $\yourNorm{}$
\end{document}
或者
\documentclass{article}
\usepackage{scrbase}% provides \IfArgIsEmpty
\newcommand*{\CsTemplate}[2]{%
\expandafter\newcommand\expandafter*\csname #1\endcsname[1]{#2\IfArgIsEmpty{##1}{}{(##1)}}%
}
\CsTemplate{myNorm}{\rho}
\CsTemplate{yourNorm}{\nu}
\begin{document}
$\myNorm{5}$ vs. $\myNorm{}$ and $\yourNorm{5}$ vs. $\yourNorm{}$
\end{document}
请注意,这\IfArgIsEmpty
是空虚测试的改进版本。
解释:#1
和#2
是 outer 的参数\newcommand
,而##1
ist 是 inner 的参数。每次嵌套时都\newcommand
必须将其翻倍。#
对于新定义的命令,您还可以使用可选参数而不是空的强制参数:
\documentclass{article}
\usepackage{scrbase}% provides \IfArgIsEmpty
\newcommand*{\CsTemplate}[2]{%
\expandafter\newcommand\expandafter*\csname #1\endcsname[1][]{#2\IfArgIsEmpty{##1}{}{(##1)}}%
}
\newcommand*{\MacroTemplate}[2]{%
\newcommand*#1[1][]{#2\IfArgIsEmpty{##1}{}{(##1)}}%
}
\CsTemplate{myNorm}{\rho}
\MacroTemplate\yourNorm{\nu}
\begin{document}
$\myNorm[5]$ vs. $\myNorm$ and $\yourNorm[5]$ vs. $\yourNorm$
\end{document}
答案3
这是一个带有 的版本xparse
,使用可选参数(在我看来,这是指示可省略参数的更好方法)。
有一种方法可以使用g
而不是o
说明符与可省略对一起使用{}
。
无论如何,\expandafter...\csname ...\endcsname
都需要一个指令来构造宏名。
\documentclass{article}
\usepackage{xparse}
\makeatletter
\newcommand\MacroGenerator[2]{%
\expandafter\NewDocumentCommand\csname #1\endcsname{o}{%
\IfValueTF{##1}
{%
#2(##1)%
}{%
#2%
}
}
}
\makeatother
\begin{document}
\MacroGenerator{mynorm}{\rho}
$
\mynorm$ and $\mynorm[5]$
\end{document}