如果命令已经定义,则 \csdef{} 报告错误

如果命令已经定义,则 \csdef{} 报告错误

如果值已经定义,是否有一个版本\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}

? 

并产生输出

FooValue=第二个值//某个宏=第二个值//FooValue=第二个值//某个其他宏=第一个值//某个其他不同的宏=第一个值

当我们不顾错误强制编译时。

答案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

此类宏有多种用途:

  1. \NameToCs{foo}\foo
  2. \NameToCs\string{foo}\string\foo
  3. \NameToCs\meaning{foo}\meaning\foo
  4. \NameToCs\global\long\def{foo}...\global\long\def\foo...
  5. \NameToCs\newcommand*{foo}...\newcommand*\foo...
  6. \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}

在此处输入图片描述

相关内容