我有一个宏,它接受两个参数,一个名称和代码:
\newcommand\definesomething[2]{%
\@namedef{something@#1}##1{#2}}
\definesomething{whatever}{Code with #1}
\show\something@whatever
这工作正常,但我想改变内部定义,因此定义一个宏,该宏使用给定的代码定义一个宏:
\newcommand\definesomething[2]{%
\@namedef{something@#1}{%
% ...
\def\something##1{#2}%
% ...
}}
\definesomething{whatever}{Code with #1}
\show\something@whatever
显然这种方式行不通。但是如何正确地做到这一点(不使用xparse
)?
当然我可以在这里使用辅助宏,但恕我直言,这远不是一个好的解决方案:
\newcommand\definesomething[2]{%
\@namedef{something@@#1}##1{#2}% define helper macro
\@namedef{something@#1}{%
% ...
\expandafter\let\expandafter\something\csname something@@#1\endcsname
% ...
}}
\definesomething{whatever}{Code with #1}
\show\something@whatever
有什么想法可以做得更好吗?
附录 2019-09-14:用户界面(\definesomething{whatever}{Code with #1}
)需要保持不变,我想摆脱\@namedef{something@@#1}
每次使用时定义的额外辅助宏。如果只在使用后才定义\definesomething
就好了。\something@whatever
\definesomething{whatever}{...}
答案1
如果有 ε-TeX 扩展可用,那么您可以系统地嵌套\unexpanded
在里面\edef
。
您可以实现序列
\definesomething{⟨MacroNamePart⟩}{⟨Code with #1⟩}
→ 定义 \something@MacroNamePart
\something@MacroNamePart
→ 定义 \something{#1}
→Code with #1
如下:
\makeatletter
\newcommand\definesomething[2]{%
\expandafter\edef\csname something@#1\endcsname{%
\unexpanded{\def\something}####1\unexpanded{{#2}}%
}%
}%
\show\definesomething
\definesomething{whatever}{Code with #1}%
\show\something@whatever
\something@whatever
\show\something
\stop
每个定义级别,其中用户级宏的参数的哈希值应加倍(以便在宏扩展期间它们可以减半)需要另一个嵌套级别\unexpanded
。
根据经验法则,唯一必须做的事情不是进入的是表示通过定义的宏\unexpanded
中出现的参数的哈希和数字序列。⟨parameter texts⟩
\edef
这些定义⟨balanced texts⟩
中的 的嵌套括号也不需要放入,这使得生活变得简单。⟨definition texts⟩
\edef
\unexpanded
您可以轻松实现序列
\definesomething{⟨MacroNamePart⟩}{⟨Code with #1⟩}
→ 定义 \something@DefinitionNestLevelOne
\something@DefinitionNestLevelOne
→ 定义 \something@DefinitionNestLevelTwo
\something@DefinitionNestLevelTwo
→ 定义 \something@MacroNamePart
\something@MacroNamePart
→ 定义 \something{#1}
→Code with #1
如下:
\makeatletter
\newcommand\definesomething[2]{%
\edef\something@DefinitionNestLevelOne{%<-opening brace of \edef-definition-text needs not be in \unexpanded
% here things are surrounded by 1 \edef, thus everything that is not a parameter
% of this one \edef must be nested in 1 level of \unexpanded:
\unexpanded{\edef\something@DefinitionNestLevelTwo}{%<-opening brace of \edef-definition-text needs not be in \unexpanded
% here things are surrounded by 2 \edef, thus everything that is not a parameter
% of one of these 2 \edef must be nested in 2 levels of \unexpanded:
\unexpanded{\unexpanded{\expandafter\edef\csname something@#1\endcsname}}{%<-opening brace of \edef-definition-text needs not be in \unexpanded
% here things are surrounded by 3 \edef, thus everything that is not a parameter
% of one of these 3 \edef must be nested in 3 levels of \unexpanded:
\unexpanded{\unexpanded{\unexpanded{\def\something}}}################1\unexpanded{\unexpanded{\unexpanded{{#2}}}}%
}%<-closing brace of \edef-definition-text needs not be in \unexpanded
}%<-closing brace of \edef-definition-text needs not be in \unexpanded
}%<-closing brace of \edef-definition-text needs not be in \unexpanded
}%
\show\definesomething
\definesomething{whatever}{Code with #1}%
\show\something@DefinitionNestLevelOne
\something@DefinitionNestLevelOne
\show\something@DefinitionNestLevelTwo
\something@DefinitionNestLevelTwo
\show\something@whatever
\something@whatever
\show\something
\stop
如果没有 ε-TeX 扩展,您该怎么办?
在非常特殊的情况下,⟨Code with #1⟩
只包含#1
但不包含##1
等,您可以使用它⟨Code with #1⟩
来定义一个处理一个参数的宏,并使用多个哈希值作为参数来调用该宏来乘以哈希值。可能看起来像这样:
\makeatletter
\newcommand\definesomething[2]{%
{%
\def\tempa##1{\def\tempa{#2}}%
\tempa{########1}%
\expandafter
}\expandafter\innerdefinesomething\expandafter{\tempa}{#1}%
}%
\newcommand\innerdefinesomething[2]{%
\@namedef{something@#2}{%
% ...
\def\something####1{#1}%
% ...
}}
\show\definesomething
\definesomething{whatever}{Code with #1}%
\show\something@whatever
\something@whatever
\show\something
\stop
答案2
我不确定我是否理解了这个问题,但也许:
> \something@whatever=macro:
->\def \something ##1{Code with ##1}.
l.12 \show\something@whatever
?
> \something=macro:
#1->Code with #1.
l.16 \show\something
?
从
\makeatletter
\newcommand\definesomething[2]{%
\@namedef{something@#1}{%
% ...
\def\something####1{#2}%
% ...
}}
\definesomething{whatever}{Code with ##1}
\show\something@whatever
\something@whatever
\show\something
答案3
您可以#
使用令牌寄存器将令牌加倍。但是,这需要在主定义主体中使用\edef
和。\unexpanded
\makeatletter
\newcommand\definesomething[2]{%
\toks@={#2}%
\expandafter\edef\csname something@#1\endcsname{%
% ...(all in \unexpanded)
\def\noexpand\something####1{\the\toks@}%
% ...(all in \unexpanded)
}}
\definesomething{whatever}{Code with #1}
\show\something@whatever
\something@whatever
\show\something
控制台输出是
This is pdfTeX, Version 3.14159265-2.6-1.40.20 (TeX Live 2019) (preloaded format=pdflatex)
restricted \write18 enabled.
entering extended mode
(./as.tex
LaTeX2e <2018-12-01>
> \something@whatever=macro:
->\def \something ##1{Code with ##1}.
l.10 \show\something@whatever
?
> \something=macro:
#1->Code with #1.
l.12 \show\something