通过索引访问宏的参数

通过索引访问宏的参数

对于 pstricks 项目,我有一个包含 9 个参数的宏,每个参数都以相同的方式由宏处理。显然,我更愿意使用循环,而不是为每个参数编写 9 次相同的代码。为此,我需要通过索引访问参数。例如

\def\foo#1{...}

\def\bar#1#2#3#4#5#6#7#8#9{
   \foreach \i in {1,...,9}{
      \if ...   % parameter #\i has some property
         \bar{#\i}
      \fi
   }
}

我怎样才能做到这一点?(上面的代码显然无法编译。)

我在网上搜索了好几天,并没有发现任何令我惊讶的东西。

在此先感谢您的帮助。

答案1

参数替换仅在 TeX 扩展宏时发生,因此您无法像尝试的那样稍后通过数字访问它们。如果您想任意访问参数,您必须定义临时宏,以便您可以通过名称访问这些宏。例如:

\def\bar#1#2#3#4#5#6#7#8#9{%
  % save the parameters:
  \def\bartmpi{#1}%
  \def\bartmpii{#2}%
  \def\bartmpiii{#3}%
  \def\bartmpiv{#4}%
  \def\bartmpv{#5}%
  \def\bartmpvi{#6}%
  \def\bartmpvii{#7}%
  \def\bartmpviii{#8}%
  \def\bartmpix{#9}%
  %
  % some complex computation:
  \def\barnum{5}%
  % access the macro with \csname ..\endcsname
  \csname bartmp\romannumeral\barnum\endcsname
  }

\bar{1}{9}{2}{8}{3}{7}{4}{6}{5}

如果您只想循环遍历 1 到 9,那么您只需映射参数列表并执行一些操作,例如使用\tl_map_inline:nn(在 内部\tl_map_inline:nn,当前项目是##1):

\ExplSyntaxOn
\cs_new_eq:NN \TlMapInline \tl_map_inline:nn
\ExplSyntaxOff

\def\bar#1#2#3#4#5#6#7#8#9{%
  \TlMapInline{{#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}}
    {%
      \ifnum##1>5
        (##1)%
      \else
        [##1]%
      \fi
    }%
  }

\bar{1}{9}{2}{8}{3}{7}{4}{6}{5}

答案2

我建议不要使用 9 个单独的参数,而是使用一个带有内部分隔符的参数(这里是逗号,,可以用 进行更改\setsepchar,请参阅listofitems文档)

\documentclass{article}
\usepackage{listofitems}
\begin{document}
\newcommand\foo[2]{%
      \ifnum #1=5   % parameter #\i has some property
         \textbf{#2}/%
      \else
        #2/%
      \fi
}
\newcommand\barr[1]{%
  \readlist*\myargs{#1}%
  \foreachitem\z\in\myargs[]{\foo{\zcnt}{\z}}
}

\barr{a,bb,d, hi mom, \today,zz, d,,!!}
\end{document}

在此处输入图片描述

另一种方法是将这 9 个参数传递给递归例程。这样,如果您的文档已经使用了它,则调用语法无需更改。

\documentclass{article}
\def\foo#1{#1/}
\def\barr#1#2#3#4#5#6#7#8#9{%
  \iftrue\barrhelp{#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}\fi}
\def\barrhelp#1#2\fi{\fi\foo{#1}\ifx\relax#2\relax\else\barrhelp#2\fi}
\begin{document}
\barr{A}{B}{C}{DD}{E}{Ff}{G}{HHH}{i}
\end{document}

在此处输入图片描述

答案3

这里的答案使用了各种工具。我展示了另一种工具,\foreach来自 OpTeX。此外:由于参数在\bar宏中被读入空格分隔符,因此您可以使用\bar任意数量的参数。

\def\bar#1 {%
  \foreach #1 \do
    {%
      \ifnum##1>5
        (##1)%
      \else
        [##1]%
      \fi
    }%
}
\bar{1}{9}{2}{8}{3}{7}{4}{6}{5}{12}{1}{13}

答案4

(!!!这个答案是“学术性的”=不适用于实际使用场景!!!

\bar在 LaTeX 2ε 中已经定义,因此下面使用\FOO和代替。)\BAR

如果您确实想要这样做,则可以\foreach使用临时宏 ( \MYtempadefiner) 来在每次迭代中定义另一个临时宏 ( \MYtempa)。请记住,#在 中定义(临时)宏时,哈希 ( ) 需要加倍\foreach。在宏定义中编写宏定义时,它们也需要加倍。

\documentclass[a4paper]{article}
\usepackage{tikz}

\newcommand\FOO[1]{\par \noindent Argument is: #1}

\newcommand\BAR[9]{%
   \def\MYtempadefiner##1{%
     \def\MYtempa####1####2####3####4####5####6####7####8####9{%
       %\if parameter ##1 has some property%
         \FOO{##1}%
       %\fi
     }%
   }%
   \foreach \i in {1,...,9}{%
      %if (expansion of) \i has some property%
        \expandafter\MYtempadefiner\expandafter{\expandafter####\i}%
        \MYtempa{#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}%
      %\fi
   }%
}%

\begin{document}

\BAR{1}{2}{3}{4}{5}{6}{7}{8}{9}%

\end{document}

在此处输入图片描述

相关内容