在以下 MWE 中:
\documentclass{article}
\usepackage{etoolbox}
\usepackage{xparse}
\makeatletter
\NewDocumentCommand{\@mkCommands}{mm}{%
\expandafter\NewDocumentCommand\csname @#1\endcsname{}{%
\notblank{#2}{%
NO \MakeUppercase{#2} PROVIDED,
USE \textbackslash #1 COMMAND%
}{}%
}
\expandafter\NewDocumentCommand\csname #1\endcsname{m}{%
\expandafter\RenewDocumentCommand\csname @#1\endcsname{}{##1}%
}
}
\@mkCommands{testCmdA}{TEST-COMMAND-A}
\@mkCommands{testCmdB}{}
\NewDocumentCommand{\makePage}{}{%
A: \@testCmdA
\protected@edef\@tempa{\@testCmdB}%
\expandafter\notblank\expandafter{\@tempa}{%
B: \@testCmdB
}{}%
}
\makeatother
\begin{document}
\makePage
\end{document}
预期输出应为:
A: NO TEST COMMAND A PROVIDED, USE \testCmdA COMMAND
但实际的输出是:
A: NO TEST COMMAND A PROVIDED, USE \testCmdA COMMAND
B:
换句话说,\notblank
相信\@tempa
不是空白,尽管它应该充分\@testCmdB
扩展应该为空白。
我在这里遗漏了什么?
答案1
如果您\@testcmdB
用定义\NewDocumentCommand
,它是一个宏,因此它在(和)\protected
中保持不变。\edef
\protected@edef
我认为采用不同的方法更好,而且这种\NewDocumentCommand
方法带来的阻碍比帮助更大。
\documentclass{article}
\usepackage{etoolbox}
\makeatletter
\newcommand{\@mkCommands}[2]{%
\ifblank{#2}
{\@namedef{@#1}{}}
{%
\@namedef{@#1}{%
NO \MakeUppercase{#2} PROVIDED,
USE \texttt{\symbol{`\\}#1} COMMAND%
}%
}%
\@namedef{#1}##1{%
\global\@namedef{@#1}{##1}%
}%
}
\@mkCommands{testcmdA}{test-command-A}
\@mkCommands{testcmdB}{}
\newcommand{\makePage}{%
A: \@testcmdA
\expandafter\notblank\expandafter{\@testcmdB}{%
\\
B: \@testcmdB
}%
}
\makeatother
\begin{document}
\section{No commands given}
\makePage
\section{Command A}
\testcmdA{Here is a test}
\makePage
\section{Command B}
\testcmdB{Here is b test}
\makePage
\end{document}
这是一种相当不同的方法。我提供的不是几个命令,而是一个\@useCommand
带有两个参数的接口:命令名称(例如testcmdA
)和要使用相关标记列表的内容执行的操作,用#1
(或者##1
如果在定义内,当然是)表示。
如果\@mkCommands
与尾随可选参数一起使用,则定义的命令将被视为对用户强制执行,因此在\makePage
执行时会出现关于在文档中提供该命令的警告。否则,\@useCommand
如果相关内容仍为空,它将不被视为强制执行,并且不会对规范执行任何操作。
\documentclass{article}
\usepackage{xparse}
\makeatletter
\ExplSyntaxOn
\clist_new:N \g_gablin_makepage_commands_clist
\NewDocumentCommand{\@mkCommands}{mo}
{
\tl_new:c { g_gablin_makepage_#1_tl }
\IfValueT { #2 }
{
\clist_gput_right:Nn \g_gablin_makepage_commands_clist { #1 }
\tl_gset:cn { g_gablin_makepage_#1_tl }
{
NO ~ \tl_upper_case:n { #2 } ~ PROVIDED, ~
USE ~ \texttt{\symbol{`\\}#1} ~ COMMAND
}
}
\exp_args:Nc \NewDocumentCommand { #1 } { m }
{
\tl_gset:cn { g_gablin_makepage_#1_tl } { ##1 }
}
}
\NewDocumentCommand{\@useCommand}{mm}
{
\cs_set:Nn \__gablin_makepage_do:n { #2 }
\clist_if_in:NnTF \g_gablin_makepage_commands_clist { #1 }
{
\__gablin_makepage_do:v { g_gablin_makepage_#1_tl }
}
{
\tl_if_blank:vF { g_gablin_makepage_#1_tl }
{
\__gablin_makepage_do:v { g_gablin_makepage_#1_tl }
}
}
}
\cs_new:Nn \__gablin_makepage_do:n {}
\cs_generate_variant:Nn \__gablin_makepage_do:n { v }
\cs_generate_variant:Nn \tl_if_blank:nF { v }
\ExplSyntaxOff
\@mkCommands{testcmdA}[test-command-A]
\@mkCommands{testcmdB}
\newcommand{\makePage}{%
\@useCommand{testcmdA}{%
A: ##1
}%
\@useCommand{testcmdB}{
\\
B: ##1
}%
}
\makeatother
\begin{document}
\section{No commands given}
\makePage
\section{Command A}
\testcmdA{Here is a test}
\makePage
\section{Command B}
\testcmdB{Here is b test}
\makePage
\end{document}
输出与以前相同。
答案2
也许是这个?
问题是\NewDocumentCommand
不会扩展为简单文本。如果你想测试某些内容是否为空白,你必须确保它扩展为简单文本,即本例中的空白文本。因此,对于你想要测试的情况,你需要使用 而\def
不是\NewDocumentCommand
。
我将 放在的定义中 的定义之外\@mkCommands
。如果是空白,我使用 简单定义为。这样,在后面的测试中,就会检测到空白。\notblank{#2}
\@#1
\def
\@#1
{}
\@tempa
\notblank
\@testCmdB
\documentclass{article}
\usepackage{etoolbox}
\usepackage{xparse}
\makeatletter
\NewDocumentCommand{\@mkCommands}{mm}{%
\notblank{#2}{%
\expandafter\NewDocumentCommand\csname @#1\endcsname{}{%
NO \MakeUppercase{#2} PROVIDED,
USE \textbackslash #1 COMMAND%
}}%
{\expandafter\def\csname @#1\endcsname{}}%
\expandafter\NewDocumentCommand\csname #1\endcsname{m}{%
\expandafter\RenewDocumentCommand\csname @#1\endcsname{}{##1}%
}
}
\@mkCommands{testCmdA}{TEST-COMMAND-A}
\@mkCommands{testCmdB}{}
\NewDocumentCommand{\makePage}{}{%
A: \@testCmdA
\protected@edef\@tempa{\@testCmdB}%
\expandafter\notblank\expandafter{\@tempa}{%
B: \@testCmdB
}{}%
}
\makeatother
\begin{document}
\makePage
\end{document}