创建一个宏,该宏用于创建宏

创建一个宏,该宏用于创建宏

我想做一些类似的事情这个问题 但正在尝试做一些更简单的事情。以下宏(我想将其归因于,但不记得我在哪里学到的)

\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,而##1ist 是 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}

相关内容