考虑一下乳胶宏的这个定义:
\newcommand\createCMDMANUV[4]{%
\expandafter\@ifdefinable\csname #3#2\endcsname{%
\expandafter\xdef\csname #3#2\endcsname##1{%
\noexpand\vcenteredhbox{%
\noexpand\includegraphics[width=##1,trim=0 0 1 -1]{BD_CATIA/#4/#1.png}}%
}%
}%
}
我尝试处理空(非可选)参数。因此我尝试了这个定义,但它不起作用:
\newcommand\createCMDMANUV[4]{%
\expandafter\@ifdefinable\csname #3#2\endcsname{%
\expandafter\xdef\csname #3#2\endcsname##1{%
\noexpand\vcenteredhbox{%
\ifdefempty{##1}{\def\widthCATIA{3cm}}{\def\widthCATIA{##1}}%
\includegraphics[width=\widthCATIA,trim=0 0 1 -1]{BD_CATIA/#4/#1.png}}%
}%
}%
}
我认为这是由于定义\widthCATIA
不明确,但正确的语法是什么......
我将该命令称为\createCMDMANUV{\tA}{\tB}{\tC}{\tD}
包含字符串\tA
的命令\tD
。
例如,如果\tC
包含AVV
并\tB
包含test
宏,则构建命令\AVVtest
。
MWE(基于相同的想法):
\documentclass{standalone}
\RequirePackage{xstring}
\RequirePackage{etoolbox}
\makeatletter
\newcommand\createCMDMANUV[2]{%
\expandafter\@ifdefinable\csname #1#2\endcsname{%
\expandafter\xdef\csname #1#2\endcsname##1{%
\noexpand\textbf{##1}%
}%
}%
}
\makeatother
\begin{document}
\def\tA {AA}
\def\tB {BB}
\createCMDMANUV{\tA}{\tB}
\AABB{coucou}
\end{document}
MNWE(最小不工作示例:-)):
\documentclass{standalone}
\RequirePackage{xstring}
\RequirePackage{etoolbox}
\makeatletter
\newcommand\createCMDMANUV[2]{%
\expandafter\@ifdefinable\csname #1#2\endcsname{%
\expandafter\xdef\csname #1#2\endcsname##1{%
\ifcsempty{##1}{ \expandafter\xdef\csname ttMANU\endcsname{Ahah}}{ \expandafter\xdef\csname ttMANU\endcsname{ohoh}}%
\noexpand\textbf{\csname ttMANU\endcsname}%
}%
}%
}
\makeatother
\begin{document}
\def\tA {AA}
\def\tB {BB}
\createCMDMANUV{\tA}{\tB}
\AABB{}
\AABB{aa}
\end{document}
\ifcsempty
空测好像没做好。
我的 MNWE 解决方案:
\documentclass{standalone}
\RequirePackage{xstring}
\RequirePackage{etoolbox}
\makeatletter
\newcommand\createCMDMANUV[2]{%
\ifdefempty{##1}{\def\ttMANU{ahah}}{\def\ttMANU{ohoh}}%
\expandafter\@ifdefinable\csname #1#2\endcsname{%
\expandafter\xdef\csname #1#2\endcsname##1{%
\noexpand\ifblank{##1}{\def\noexpand\ttMANU{ahah}}{\def\noexpand\ttMANU{##1}}%%
\noexpand\textbf{\noexpand\ttMANU}%
}%
}%
}
\makeatother
\begin{document}
\def\tA {AA}
\def\tB {BB}
\createCMDMANUV{\tA}{\tB}
\AABB{}
\AABB{aa}
\end{document}
答案1
\ifdefempty
您正在尝试在定义时进行扩展;但您应该使用\ifblank
;
\newcommand\createCMDMANUV[4]{%
\expandafter\@ifdefinable\csname #3#2\endcsname{%
\expandafter\xdef\csname #3#2\endcsname##1{%
\noexpand\vcenteredhbox{%
\noexpand\ifblank{##1}{\def\noexpand\widthCATIA{3cm}}{\def\noexpand\widthCATIA{##1}}%
\noexpand\includegraphics[width=\noexpand\widthCATIA,trim=0 0 1 -1]{BD_CATIA/#4/#1.png}}%
}%
}%
}
如果我打电话
\def\tA{AA}\def\tB{test}\def\tC{AVV}\def\tD{DD}
\createCMDMANUV{\tA}{\tB}{\tC}{\tD}
\show\AVVtest
我收到以下回复:
> \AVVtest=macro:
#1->\vcenteredhbox {\ifblank {#1}{\def \widthCATIA {3cm}}{\def \widthCATIA {#1}
}\includegraphics [width=\widthCATIA ,trim=0 0 1 -1]{BD_CATIA/DD/AA.png}}.
使用起来更简单expl3
:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand\createCMDMANUV { mmmm }
{
\guuk_create_cmd_manuv:xxxx { #1 } { #2 } { #3 } { #4 }
}
\tl_new:N \l__guuk_width_catia_tl
\cs_new_protected:Nn \guuk_create_cmd_manuv:nnnn
{
\cs_new_protected:cpn { #3#2 } ##1
{
\vcenteredhbox
{
\tl_if_empty:nTF { ##1 }
{ \tl_set:Nn \l__guuk_width_catia_tl { 3cm } }
{ \tl_set:Nn \l__guuk_width_catia_tl { ##1 } }
\includegraphics[width=\l__guuk_width_catia_tl,trim=0 ~ 0 ~ 1 ~ -1]{BD_CATIA/#4/#1.png}
}
}
}
\cs_generate_variant:Nn \guuk_create_cmd_manuv:nnnn { xxxx }
\ExplSyntaxOff
\def\tA{AA}\def\tB{test}\def\tC{AVV}\def\tD{DD}
\createCMDMANUV{\tA}{\tB}{\tC}{\tD}
\show\AVVtest
答案是
> \AVVtest=\protected\long macro:
#1->\vcenteredhbox {\tl_if_empty:nTF {#1}{\tl_set:Nn \l__guuk_width_catia_tl {3
cm}}{\tl_set:Nn \l__guuk_width_catia_tl {#1}}\includegraphics [width=\l__guuk_w
idth_catia_tl ,trim=0 0 1 -1]{BD_CATIA/DD/AA.png}}.
怎么运行的
我定义了一个带有四个参数的“用户级命令”
\createCMDMANUV
。它的任务只是将参数传递给\guuk_create_cmd_manuv:xxxx
我定义了该
\guuk_create_cmd_manuv:nnnn
函数;“4”n
表示它是一个具有四个“正常”参数的宏。此函数反过来根据传递的参数定义一个新的宏;它的作用
\cs_new_protected:cpn
是类似于\expandafter\def\csname ...\endcsname
,但添加了“未定义性测试”,因此\cs_new_protected:cpn { <tokens> } #1 { ... }
你在做什么
\expandafter\def\csname <tokens>\endcsname##1{...}
根据要求,构造的宏有一个参数,用 测试该参数是否为空,
\tl_if_blank:nTF
如果参数为空则返回第二个参数,否则返回第三个参数。此测试与 相同etoolbox
\ifblank
;代码只是将内部标记列表设置为参数,如果不是空则设置为3cm
构建函数的内部代码与使用传统方法构建的完全相同,但是没有任何
\noexpand
最后的技巧:
\cs_generate_variant:Nn \guuk_create_cmd_manuv:nnnn { xxxx }
我们从所述函数中定义另一个名为的函数
\guuk_create_cmd_manuv:xxxx
,当调用时,首先对其四个参数进行完全扩展,然后将扩展的参数作为普通参数传递给\guuk_create_cmd_manuv:nnnn
请注意,在编程环境中,
\ExplSyntaxOn
和之间\ExplSyntaxOff
,空格和空行会被忽略,因此无需担心保护行尾。唯一的小麻烦是想要的空间必须明确地插入上述键~
的值中trim
。
答案2
我删除了我的第一个答案,因为看起来你的代码太复杂了(对于许多用户来说通常都是这样:)。首先,你必须问为什么我需要使用\xdef
普通的\gdef
?我不明白为什么。因此,您的示例可以适用于\gdef
:
\def\createCMDMANUV#1#2#3#4{%
\expandafter\@ifdefinable\csname #3#2\endcsname{%
\expandafter\gdef\csname #3#2\endcsname##1{%
\vcenteredhbox{%
\includegraphics[width=\widthCATIA{##1},trim=0 0 1 -1]{BD_CATIA/#4/#1.png}}%
}%
}%
}
\def\withCATIA#1{\ifx^#1^3cm\else#1\fi}
编辑(回应关于声明期间参数扩展的评论)。如果您需要在代码中使用扩展参数\declaremacro
,那么您可以考虑以下代码:
\def\delcleremacro#1#2#3#4{\edef\tmp{\noexpand\declaremacroA{#1}{#2}{#3}{#4}\tmp}
\def\declaremacroA#1#2#3#4{%
\expandafter\gdef\csname #3#2\endcsname##1{%
... here is my complicated macro, which uses declared
and {\bf expanded} parameters #1, #2, #3, #4 and one real parameter ##1.
I need not to use fifty times \noexpand here.
The test of empty parameter ##1 can be done by
\ifx^##1^empty\else nonempty\fi or (more robust but nonexpandable)
\def\tmp{##1}\ifx\tmp\empty \def\tmp{3cm}\else\def\tmp{##1}\fi
and you can use \tmp in your meaning of \widthCATIA.
Here is no \noexpand problem.
}}