如何获取宏中的参数数量?

如何获取宏中的参数数量?

我正在编写一个包,我需要获取宏中的参数数量。比如说,用户必须定义​​一个宏

\def\usermacro#1#2....

然后他打电话

\dosomestuffdefinedinmypackage

并且此命令\usermacro根据其参数的数量以某种方式获取和使用它,所以我需要找到一种方法来了解它。

最好不要使用其他软件包,我想要了解它是如何工作的,而不是学习咒语。谢谢!

答案1

下面定义了一个\getnumargs接受两个参数的宏。第一个是任意宏,第二个是应该存储结果的宏。

它会将第一个宏所采用的参数数量存储在第二个宏中。

警告:这只会获取该宏将采用的参数数量,不会多也不会少。如果宏采用分隔参数,它也会失败。其中包括一些从技术上讲是正确的示例,但很可能不会返回您想要的内容。

\documentclass[]{article}

\makeatletter
\edef\getnumargs@ifmacro
  {%
    \noexpand\expandafter\noexpand\getnumargs@ifmacro@
      \noexpand\getnumargs@meaning\relax\noexpand\getnumargs@ifmacro@true
      \detokenize{macro:}\relax\noexpand\getnumargs@ifmacro@false
  }
\def\getnumargs@ifmacro@true#1\getnumargs@ifmacro@false#2{#2}
\expandafter\def\expandafter\getnumargs@ifmacro@
    \expandafter#\expandafter1\detokenize{macro:}#2\relax
  {}
\newcommand*\getnumargs@ifmacro@false[1]
  {%
    \PackageError{Alex}{}{Not a macro!}%
    \def\getnumargs@num{0}%
  }
\newcommand\getnumargs[2]
  {%
    \begingroup
      \edef\getnumargs@meaning{\meaning#1}%
      \getnumargs@ifmacro
        {%
          \expandafter\getnumargs@settmp\expandafter{\getnumargs@meaning}%
          \getnumargs@getnum
        }%
      \expandafter
    \endgroup
    \expandafter\def\expandafter#2\expandafter{\getnumargs@num}%
  }
\newcommand\getnumargs@settmp[1]
  {%
    \expandafter\def\expandafter\getnumargs@tmp
      \getnumargs@getargs#1\relax##1##2##3\relax{##2}%
  }
\expandafter\def\expandafter\getnumargs@getargs
    \expandafter#\expandafter1\detokenize{macro:}#2->#3\relax
  {#2}
\edef\getnumargs@getnum
  {%
    \edef\noexpand\getnumargs@num
      {%
        \noexpand\the\noexpand\numexpr
          \noexpand\getnumargs@tmp
          \string#1\string#2\string#3%
          \string#4\string#5\string#6%
          \string#7\string#8\string#9%
          .{10}\relax
          -1\relax
      }%
  }

\makeatother

\newcommand\noargs{}
\newcommand\onearg   [1]{}
\newcommand\twoargs  [2]{}
\newcommand\threeargs[3]{}
\newcommand\fourargs [4]{}
\newcommand\fiveargs [5]{}
\newcommand\sixargs  [6]{}
\newcommand\sevenargs[7]{}
\newcommand\eightargs[8]{}
\newcommand\nineargs [9]{}

\begin{document}
\getnumargs\section\tmp
\tmp

\getnumargs\texttt\tmp
\tmp

\getnumargs\emph\tmp
\tmp

\getnumargs\noargs\tmp
\tmp

\getnumargs\onearg\tmp
\tmp

\getnumargs\twoargs\tmp
\tmp

\getnumargs\threeargs\tmp
\tmp

\getnumargs\fourargs\tmp
\tmp

\getnumargs\fiveargs\tmp
\tmp

\getnumargs\sixargs\tmp
\tmp

\getnumargs\sevenargs\tmp
\tmp

\getnumargs\eightargs\tmp
\tmp

\getnumargs\nineargs\tmp
\tmp
\end{document}

答案2

灵感来自user202729 的回答,这里有一个更简单的编码:

\documentclass{article}

\ExplSyntaxOn

\NewExpandableDocumentCommand{\getnumargs}{m}
  {
    \int_eval:n { \str_count:e { \cs_argument_spec:N #1 } / 2 }
  }
\cs_generate_variant:Nn \str_count:n { e }

\ExplSyntaxOff


\newcommand\noargs{}
\newcommand\onearg   [1]{}
\newcommand\twoargs  [2]{}
\newcommand\threeargs[3]{}
\newcommand\fourargs [4]{}
\newcommand\fiveargs [5]{}
\newcommand\sixargs  [6]{}
\newcommand\sevenargs[7]{}
\newcommand\eightargs[8]{}
\newcommand\nineargs [9]{}

\begin{document}

\getnumargs\texttt

\getnumargs\emph

\getnumargs\noargs

\getnumargs\onearg

\getnumargs\twoargs

\getnumargs\threeargs

\getnumargs\fourargs

\getnumargs\fiveargs

\getnumargs\sixargs

\getnumargs\sevenargs

\getnumargs\eightargs

\getnumargs\nineargs

\texttt{\edef\test{\getnumargs\nineargs}\meaning\test}

\end{document}

所需扩展步骤数大于 2,但这并不重要。想法是,如果步骤数为 1,很好,我们可以根据o需要将其用作参数说明符;否则使用e

在此处输入图片描述

相关内容