如果值已经定义,是否有一个版本\csdef{}{}
会报告错误?下面的 MWE 编译正常,因为没有检查已经定义的宏,并产生:
我想替换它csdef
,以便它报告类似于重复的错误情况\newcommand
。
代码:
\documentclass{article}
\usepackage{etoolbox}
\newcommand*{\FooValue}{First Value}
\csdef{FooValue}{Second Value}
\csdef{Some Macro}{First Value}
\csdef{Some Macro}{Second Value}
\begin{document}
FooValue=\csuse{FooValue}
Some Macro=\csuse{Some Macro}
\end{document}
答案1
我认为 中没有这样的宏etoolbox
。它的\cs..def...
宏全部反映了您可以执行的操作\def
,并且\def
没有检查它是否覆盖了任何内容。
这里有两个可能的解决方案。一个是基本\csdef
测试,另一个是\newcommand
(\csname ...\endcsname
测试也是如此\necommand
)。
在\csdef
测试中,我将 引入\csdef
到一次性宏 ( \my@etb@throwaway
) 中,这样我就不必收集和吞噬\csdef
我自己的可能参数。(当然,这意味着你不应该\my@etb@throwaway
在任何地方使用 ( 。)
以下 MWE
\documentclass{article}
\usepackage{etoolbox}
\newcommand*{\FooValue}{First Value}
\csdef{FooValue}{Second Value}
\csdef{Some Macro}{First Value}
\csdef{Some Macro}{Second Value}
\newcommand*{\csdefifundef}[1]{%
\ifcsundef{#1}
{\csdef{#1}}
{\PackageError{etoolbox}
{Command sequence '#1' already defined}
{You can only define undefined commands with \string\csdefifundef}%
\csdef{my@etb@throwaway}}}
\csdefifundef{Some Other Macro}{First Value}
\csdefifundef{Some Other Macro}{Second Value}
\newcommand*{\csnewcommand}[1]{%
\expandafter\newcommand\expandafter{\csname #1\endcsname}}
\csnewcommand{Some Other Different Macro}{First Value}
\csnewcommand{Some Other Different Macro}{Second Value}
\begin{document}
FooValue=\csuse{FooValue}
Some Macro=\csuse{Some Macro}
FooValue=\csuse{FooValue}
Some Other Macro=\csuse{Some Other Macro}
Some Other Different Macro=\csuse{Some Other Different Macro}
\end{document}
抛出错误
! Package etoolbox Error: Command sequence 'Some Other Macro' already defined.
See the etoolbox package documentation for explanation.
Type H <return> for immediate help.
...
l.18 \csdefifundef{Some Other Macro}{Second Value}
?
! LaTeX Error: Command \Some Other Different Macro already defined.
Or name \end... illegal, see p.192 of the manual.
See the LaTeX manual or LaTeX Companion for explanation.
Type H <return> for immediate help.
...
l.25 ...{Some Other Different Macro}{Second Value}
?
并产生输出
当我们不顾错误强制编译时。
答案2
TeXbook 解释了定义宏时的一个很好的特性:在⟨parameter text⟩
宏定义中,你可以使用#{
-notation 来表示宏,它的最后一个参数将由左花括号分隔{
,与其他参数分隔符不同,它将被重新插入,就像它一直留在原处一样。
因此,我有时会使用一种宏机制\NameToCs
来处理由左花括号()分隔的参数{
和嵌套在花括号中的另一个参数。
嵌套在花括号中的参数表示通过..⟨control sequence token⟩
构造的名称。\csname
\endcsname
\NameToCs
工作原理如下:
\NameToCs⟨stuff not in curly braces⟩{NameOfCs}
→
⟨stuff not in curly braces⟩\NameOfCs
(如果您只希望获取控制序列令牌\NameOfCs
,那么您可以留空⟨stuff not in curly braces⟩
:)\NameToCs{NameOfCs} → \NameOfCs
\makeatletter
\newcommand\exchange[2]{#2#1}%
\@ifdefinable\NameToCs{\long\def\NameToCs#1#{\romannumeral0\innerNameToCs{#1}}}%
\newcommand\innerNameToCs[2]{\expandafter\exchange\expandafter{\csname#2\endcsname}{ #1}}%
\makeatother
此类宏有多种用途:
\NameToCs{foo}
→\foo
\NameToCs\string{foo}
→\string\foo
\NameToCs\meaning{foo}
→\meaning\foo
\NameToCs\global\long\def{foo}...
→\global\long\def\foo...
\NameToCs\newcommand*{foo}...
→\newcommand*\foo...
\NameToCs\NameToCs\global\let{foo}={bar}
→\NameToCs\global\let\foo={bar}
→\global\let\foo=\bar
使用示例 5 可应用于⟨balanced text⟩
宏的定义中\csnewcommand
:
\newcommand*\csnewcommand{\NameToCs\newcommand}%
将各个部分组合到 MWE 中:
\documentclass{article}
% Define the macro \NameToCs:
\makeatletter
\newcommand\exchange[2]{#2#1}%
\@ifdefinable\NameToCs{\long\def\NameToCs#1#{\romannumeral0\innerNameToCs{#1}}}%
\newcommand\innerNameToCs[2]{\expandafter\exchange\expandafter{\csname#2\endcsname}{ #1}}%
\makeatother
% Define \csnewcommand and \csrenewcommand and \csProvideCommand and \csDeclareRobustCommand
\newcommand*\csnewcommand{\NameToCs\newcommand}%
\newcommand*\csrenewcommand{\NameToCs\renewcommand}%
\newcommand*\csProvideCommand{\NameToCs\ProvideCommand}%
\newcommand*\csDeclareRobustCommand{\NameToCs\DeclareRobustCommand}%
\csnewcommand*{FooValue}{FooValue's First Value}
% This throws an error:
%\csnewcommand*{FooValue}{FooValue's Second Value}
% This does not throw an error.
%\csrenewcommand*{FooValue}{FooValue's Second Value}
\csnewcommand*{Some Macro}{Some Macro's First Value}
% This throws an error:
%\csnewcommand*{Some Macro}{Some Macro's Second Value}
% This does not throw an error.
%\csrenewcommand*{Some Macro}{Some Macro's Second Value}
\csnewcommand*{Some Other Macro}{Some Other Macro's First Value}
% This throws an error:
%\csnewcommand*{Some Other Macro}{Some Other Macro's Second Value}
% This does not throw an error.
\csrenewcommand*{Some Other Macro}{Some Other Macro's Second Value}
\begin{document}
\noindent
\texttt{\NameToCs\string{FooValue}} is defined as \texttt{\NameToCs\meaning{FooValue}}\\
Expanding \texttt{\NameToCs\string{FooValue}} yields: \NameToCs{FooValue}
\bigskip
\noindent
\texttt{\NameToCs\string{Some Macro}} is defined as \texttt{\NameToCs\meaning{Some Macro}}\\
Expanding \texttt{\NameToCs\string{Some Macro}} yields: \NameToCs{Some Macro}
\bigskip
\noindent
\texttt{\NameToCs\string{Some Other Macro}} is defined as \texttt{\NameToCs\meaning{Some Other Macro}}\\
Expanding \texttt{\NameToCs\string{Some Other Macro}} yields: \NameToCs{Some Other Macro}
\end{document}