我正在尝试编写一个宏\RR
,允许我输入\mathbb{R}
文本,并带有一个可选的指数参数。所需的功能如下所示:
I can now write \RR\ in text. % --> produces: I can now write $\mathbb{R}$ in text.
Blah blah \RR[m+n] blah blah. % --> produces: Blah blah $\mathbb{R}^{m+n}$ blah blah
对于固定字母(例如 R),目前可以通过以下方式实现:
\NewDocumentCommand{\RR}{o}{\ensuremath{\mathbb{R}\IfNoValueF{#1}{^{#1}}}}
我想为其他字母定义类似的命令。我意识到最实用的方法是为每个额外的字母编写上述版本。但是,出于学习目的,我很好奇如何使用\foreach
。我尝试过类似
\foreach \letter in {F,N,Z,Q,R,C,H}{
\expandafter\NewDocumentCommand\csname\letter\letter\endcsname{o}{\ensuremath{\mathbb{\letter}\IfNoValueF{#1}{^{#1}}}}
}
上述命令无法创建。尝试
I can now write \RR\ in text. % --> should produce: I can now write $\mathbb{R}$ in text.
Blah blah \RR[m+n] blah blah. % --> should produce: Blah blah $\mathbb{R}^{m+n}$ blah blah
Illegal parameter number in definition of \pgffor@body
在定义点(内部foreach
)产生错误,Undefined control sequence
当我尝试使用\RR
如上所示时。
至少,它似乎缺少了类似\expandafter
或\noexand
的东西,我曾见过 用它\edef
来控制 的扩展\ensuremath{\mathbb{\letter}\IfNoValueF{#1}{^{#1}}}
。任何帮助都将不胜感激,谢谢!
答案1
您的代码存在一些问题。第一个会产生错误,即\foreach
执行了(等同于)的操作\def\pgffor@body{<loop code>}
,如果<loop code>
包含#
,则会出现错误(尝试一下)。此问题的解决方法是将加倍#
,因此
\IfNoValueF{##1}{^{##1}}
那么就不会有错误了...但是你的命令也不会起作用:D
第一个障碍是\foreach
在循环代码周围创建一个组,因此本地分配会丢失,并且您现在可能已经猜到了,\NewDocumentCommand
在本地范围内创建命令(\global
在它前面添加也不起作用),因此\foreach
结束后您的命令将不再存在。\foreach
这不是定义命令(或者在我看来,一般的编程任务)的好选择。
第二个问题是您的命令定义为(简化):
\def\FF#1{\ensuremath {\mathbb {\letter }\IfNoValueF {#1}{^{#1}}}}
\def\NN#1{\ensuremath {\mathbb {\letter }\IfNoValueF {#1}{^{#1}}}}
\def\ZZ#1{\ensuremath {\mathbb {\letter }\IfNoValueF {#1}{^{#1}}}}
...
那么是什么\letter
? 很有可能H
,因为它是循环中的最后一个值,但是最新版本的pgffor
它是未定义的(或者是您意想不到的东西)。
我建议一次性解决这两个问题,就是不要使用\foreach
。而是使用不进行分组的循环构造,并且最好允许循环项而不是#1
宏。 expl3
符合\clist_map_inline:nn
要求:
\RequirePackage{xparse}
\ExplSyntaxOn
\clist_map_inline:nn { F,N,Z,Q,R,C,H }
{
\exp_args:Nc \NewDocumentCommand { #1#1 } { o }
{\ensuremath{\mathbb{#1}\IfNoValueF{##1}{^{##1}}}}
}
\ExplSyntaxOff
(\exp_args:Nc \macro { <tokens> }
是\expandafter\macro\csname <tokens>\endcsname
)。
答案2
您没有提到,但我假设您使用的是 pgf 中的循环,该循环在每次迭代周围放置一个组。使用不同的构造(例如使用 expl3 映射列表)会更容易。
\documentclass{article}
\usepackage{amsfonts}
\ExplSyntaxOn
\clist_map_inline:nn{F,N,Z,Q,R,C,H}{
\expandafter\NewDocumentCommand\csname#1#1\endcsname{o}{\ensuremath{\mathbb{#1}\IfNoValueF{##1}{^{##1}}}}
}
\ExplSyntaxOff
\begin{document}
\FF \FF[x]
\QQ \QQ[2]
\ZZ \ZZ[\infty]
\end{document}
答案3
\documentclass{article}
\usepackage{amssymb,listofitems}
\def\ZZstencil#1#2\relax{%
\mathbb{#1}\ifx\relax#2\relax\else^{#2}\fi
}
\def\ZZargs{[1][]}
\newcommand\makeZZ[1]{%
\readlist\mylist{#1}%
\foreachitem\z\in\mylist[]{%
\expandafter\newcommand\csname\z\z\expandafter\expandafter
\expandafter\endcsname\expandafter\ZZargs\expandafter{%
\expandafter\ZZstencil\z####1\relax}%
}%
}
\begin{document}
\makeZZ{F,N,Z,Q,R,C,H}
$\RR$
$\RR[a+b]$
$\ZZ$
$\ZZ[(a+b)/2]$
$\HH$$\HH[x]$
\end{document}
如果你真的需要它\ensuremath
,那么这个:
\documentclass{article}
\usepackage{amssymb,listofitems}
\def\ZZstencil#1#2\relax{%
\mathbb{#1}\ifx\relax#2\relax\else^{#2}\fi
}
\def\ZZargs{[1][]}
\newcommand\makeZZ[1]{%
\readlist\mylist{#1}%
\foreachitem\z\in\mylist[]{%
\expandafter\newcommand\csname\z\z\expandafter\expandafter
\expandafter\endcsname\expandafter\ZZargs\expandafter{%
\expandafter\ensuremath\expandafter{\expandafter
\ZZstencil\z####1\relax}}%
}%
}
\begin{document}
\makeZZ{F,N,Z,Q,R,C,H}
\RR\ \RR[a+b]\ \ZZ\ \ZZ[(a+b)/2]\ $\HH\HH[x]$
\end{document}
答案4
我会用expl3
它完成工作,但与其他答案的使用方式不同。
\documentclass{article}
\usepackage{amssymb}
\ExplSyntaxOn
\NewDocumentCommand{\makenumberset}{m}
{
\clist_map_inline:nn { #1 }
{
\cs_new_protected:cpn { ##1##1 } { \numberset { ##1 } }
}
}
\NewDocumentCommand{\numberset}{mo}
{
\ensuremath { \mathbb{#1}\IfValueT{#2}{^{#2}} }
}
\ExplSyntaxOff
\makenumberset{F,N,Z,Q,R,C,H}
\begin{document}
In text \RR\ and \RR[m+n]; also in math $\RR$ and $\RR[m+n]$.
In text \ZZ\ and \ZZ[m+n]; also in math $\FF$ and $\FF[m+n]$.
And also \numberset{A} or \numberset{A}[m+n].
\end{document}
注意偶尔出现的字母的抽象命令。
我当然会不是使用它没有任何实际用途。能够输入文本,但有时必须记住后面的反斜杠,\ensuremath
这没什么好处。有了它,您就不会遇到这个问题。\RR
$\RR$