使用宏定义不带反斜杠的 \NewDocumentCommand 宏

使用宏定义不带反斜杠的 \NewDocumentCommand 宏

或者正如沃纳简化的那样:“如何在 xparse 中定义不带反斜杠的命令“。


背景:

我正在尝试设置一个宏来为我定义一个宏(它还将执行下面的 MWE 中不是必不可少的一些其他事情)。

\NumericalToNumber下面的第一个版本通过传入来设置宏#1。请注意\名称中的。

\DefineMacro{\NumericalToNumber}{%
    {one}{1}%
    {two}{2}%
    {three}{3}% 
    {four}{4}% 
}%

这正是我想要的。

在此处输入图片描述

但是,要执行我需要在 中完成的“其他事情” \DefineMacro,我需要提供不带反斜杠的宏名称。因此,我认为将调用更改为不带反斜杠\的名称很容易,并使用csuse{}etoolbox生成名称(而不是通常的\expandafter\csname...\endcsname):

\DefineMacro{NumericalToNumber}{%
    {one}{1}%
    {two}{2}%
    {three}{3}% 
    {four}{4}% 
}%

但我似乎无法让这个版本运行。

我也尝试坚持使用第一个版本,并采用来自如何删除参数尾部的转义字符?但那对我来说不起作用。基本上,“其他事情”所需的代码已经可以运行,所以我更希望使用第二个版本。


代码:作品:\使用\DefineMacro

\documentclass{article}
\usepackage{xparse}
\usepackage{xstring}
    
\NewDocumentCommand{\DefineMacro}{m m}{%
    % #1 = command name to be defined (WITH backslash).
    % #2 = pairs of {<property name>}{<propery value} (same as what \ItStrEqCase accepts)
    \NewDocumentCommand{#1}{s O{UNKNOWN}}{%
        \IfStrEqCase{##2}{%
            #2% 
        }[\fbox{Unknown property name='##2' in \string#1.}]%
    }%
}%

\DefineMacro{\NumericalToNumber}{%
    {one}{1}%
    {two}{2}%
    {three}{3}% 
    {four}{4}% 
}%

\begin{document}
\NumericalToNumber[two]

\NumericalToNumber[four]

\NumericalToNumber[ten]
\end{document}

\代码:没有in则无法工作\DefineMacro

\documentclass{article}
\usepackage{etoolbox}
\usepackage{xparse}
\usepackage{xstring}
    
\NewDocumentCommand{\DefineMacro}{m m}{%
    % #1 = command name to be defined (withOUT backslash).
    % #2 = pairs of {<property name>}{<propery value} (same as what \ItStrEqCase accepts)
    \NewDocumentCommand{\csuse{#1}}{s O{UNKNOWN}}{% <---- Use of \csuse here
        \IfStrEqCase{##2}{%
            #2% 
        }[\fbox{Unknown property name='##2' in \string#1.}]%
    }%
}%

\DefineMacro{NumericalToNumber}{% <--- No backslash here in #1.
    {one}{1}%
    {two}{2}%
    {three}{3}% 
    {four}{4}% 
}%

\begin{document}
\NumericalToNumber[two]

\NumericalToNumber[four]

\NumericalToNumber[ten]
\end{document}

答案1

我不确定这是预期的结果,但是

\expandafter\NewDocumentCommand{\csname#1\endcsname} 

不起作用,但是

\expandafter\NewDocumentCommand\csname#1\endcsname 

确实如此。第一种方法尝试将宏的名称 (NumericalToNumber) 视为参数类型列表,从而导致有关未知“N”参数类型的错误。

\documentclass{article}


\usepackage{etoolbox}
\usepackage{xparse}
\usepackage{xstring}

\DeclareDocumentCommand{\DefineMacro}{mm}{%
  % #1 = command name to be defined (withOUT backslash).
  % #2 = pairs of {<property name>}{<propery value} (same as what \ItStrEqCase accepts)
  \expandafter\DeclareDocumentCommand\csname#1\endcsname{s O{UNKNOWN}}{%
    \IfStrEqCase{##2}{%
      #2% 
        }[\fbox{Unknown property name='##2' in \string#1.}]%
      }%
}

\DeclareDocumentCommand{\OtherDefineMacro}{mm}{%
  % #1 = command name to be defined (withOUT backslash).
  % #2 = pairs of {<property name>}{<propery value} (same as what \ItStrEqCase accepts)
  \expandafter\NewDocumentCommand\csname#1\endcsname{s O{UNKNOWN}}{%
    \IfStrEqCase{##2}{%
      #2% 
        }[\fbox{Unknown property name='##2' in \string#1.}]%
      }%
}


\DefineMacro{NumericalToNumber}{% <--- No backslash here in #1.
    {one}{1}%
    {two}{2}%
    {three}{3}% 
    {four}{4}% 
}%

\OtherDefineMacro{OtherNumericalToNumber}{% <--- No backslash here in #1.
    {one}{1}%
    {two}{2}%
    {three}{3}% 
    {four}{4}% 
}%


\begin{document}
\NumericalToNumber[two]

\NumericalToNumber[four]

\OtherNumericalToNumber[eight]

\NumericalToNumber[ten]
\end{document}

在此处输入图片描述

我也提供了一个版本\DeclareDocumentCommand

答案2

这是一个非常常见的问题:您必须在\NewDocumentCommand开始其工作之前提供一个符号标记(宏名):

\expandafter\NewDocumentCommand\csname ...\endcsname

是解决方案;越复杂

\expandafter\NewDocumentCommand\expandafter{\csname ...\endcsname}

也可以。

有一种更巧妙的方法,可以避免这样做\expandafter

\documentclass{article}
\usepackage{xparse}

\newcommand{\SSErrorBox}[1]{\fbox{#1}}
\newcommand{\command}[1]{\texttt{#1}}


\ExplSyntaxOn
\NewDocumentCommand{\DefineMacro}{m m}
 {
  % #1 = command name to be defined (without backslash).
  % #2 = pairs of {<property name>}{<property value>}
  \grill_define_macro:cn { #1 } { #2 }
 }

\cs_new_protected:Npn \grill_define_macro:Nn #1 #2
 {
  \NewDocumentCommand{#1}{s O{UNKNOWN}}
   {
    \str_case:nnF { ##2 } { #2 }
     { \SSErrorBox{Unknown~property~name="##2"~in~"\command{\string#1}".} }
   }
 }
\cs_generate_variant:Nn \grill_define_macro:Nn { c }
\ExplSyntaxOff

\DefineMacro{NumericalToNumber}{% <--- No backslash here in #1.
  {one}{1}
  {two}{2}
  {three}{3} 
  {four}{4}
}

\begin{document}

X\NumericalToNumber[two]X

X\NumericalToNumber[four]X

X\NumericalToNumber[ten]X

\end{document}

\DefineMacro只是将控制权传递给\grill_define_macro:cn。然后我们定义\grill_define_macro:Nn;根据 中的约定expl3,此函数需要两个参数:一个无括号的单个标记(N)和一个通常带括号的参数(n)。

参数#1是要定义的宏\NewDocumentCommand#2是成对的列表。我们可以使用,{<key>}{<value>}而不是,它被称为\IfStrEqCase\str_case:nnF

\str_case:nnF
 { ##2 } % the second argument to the macro
 { #2 }  % the list of properties
 { ... } % what to do when there's no match

当然,\IfStrEqCase如果您愿意,您可以自由使用,只需记住,在编程环境中\ExplSyntaxOn/\ExplSyntaxOff空格会被忽略,并且必须将所需空格提供为~

\grill_define_macro:cn最后,定义了变体;神奇的事情就在这里发生:c意味着必须用大括号括起来参数,并从中构建一个符号标记 \grill_define_macro:Nn被执行。

在此处输入图片描述

我使用了一些 X 来表明没有伪造的空间潜入。


\NewDocumentCommand这里是的定义xparse.sty

\cs_new_protected:Npn \NewDocumentCommand #1#2#3
  {
    \cs_if_exist:NTF #1
      {
        \__msg_kernel_error:nnx { xparse } { command-already-defined }
          { \token_to_str:N #1 }
      }
      { \__xparse_declare_cmd:Nnn #1 {#2} {#3} }
  }

如果这是

\cs_new_protected:Npn \xparse_new_document_command:Nnn #1#2#3
  {
    \cs_if_exist:NTF #1
      {
        \__msg_kernel_error:nnx { xparse } { command-already-defined }
          { \token_to_str:N #1 }
      }
      { \__xparse_declare_cmd:Nnn #1 {#2} {#3} }
  }
\cs_set_eq:NN \NewDocumentCommand \xparse_new_document_command:Nnn

你可以在你的文档中简单地说,

\ExplSyntaxOn
\cs_generate_variant:Nn \xparse_new_document_command:Nnn { c }
\cs_set_eq:NN \NewDocumentCommandName \xparse_new_document_command:cnn
\ExplSyntaxOff

并且您可以使用不\NewDocumentCommandName{<name>}{<args>}{<code>}<name>反斜杠的宏名称。

可能有充分的理由不在包中执行此操作。

不过,你可以自己做:

\ExplSyntaxOn
\cs_set_eq:NN \grill_new_document_command:Nnn \NewDocumentCommand
\cs_generate_variant:Nn \grill_new_document_command:Nnn { c }
\cs_set_eq:NN \NewDocumentCommandName \grill_new_document_command:cnn
\ExplSyntaxOff

然而,我更喜欢上面概述的策略。

答案3

我以为标准\cs_generate_variant:Nn当不可用时(如本例),方法是使用\exp_args:??。在这种情况下

\ExplSyntaxOn
\NewDocumentCommand \DefineMacro { }
  { \exp_args:Nc \NewDocumentCommand }
\ExplSyntaxOff

或者,没有必要\ExplSyntax..

\NewDocumentCommand\DefineMacro{}
  {\csname exp_args:Nc\endcsname\NewDocumentCommand}
 %{\csuse{exp_args:Nc}\NewDocumentCommand}

相关内容