需要分组和扩展控制方面的帮助

需要分组和扩展控制方面的帮助

我正在尝试定义宏,它接受一个分隔列表并将每个元素传递给一个宏(该宏接受一个参数)。我有完整的工作版本,可以迭代

  1. 列表中的所有元素,
  2. 第一个 n,(其中 n 作为宏参数给出)但如果小于 n,则不添加空值,并且
  3. 前 n 个,但如果需要则添加空元素。

它们使用分组使所有定义都成为本地定义,但实际上在组结束后执行宏(这是必不可少的)。我已经用各种嵌套宏测试了它们,这些宏使用不同的分隔符再次调用它们,它们似乎很健壮。但是,当我尝试在另一个宏中使用它们时,我遇到了一个非常奇怪的问题,该宏应该采用列表的前 n 个元素(如果需要,末尾带有空元素)并调用接受 n 个参数的宏。如果我从上述宏的第 3 版复制粘贴大部分代码,一切都很好。但是,如果我尝试调用此宏,要求它为每个列表元素调用一个本地定义的宏,该宏应该将这些元素附加到(本地)标记列表中,则每次迭代后都会清空标记列表……我认为问题出在将标记附加到列表的辅助宏中,如下所示,但我找不到原因!它们在其他情况下按预期工作。我一定是错过了一些明显而愚蠢的东西,我很抱歉。以下是相关的宏:

\documentclass{article}

\usepackage{etoolbox}
\makeatletter
\newtoks\tmp@toks

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% append token #1 to token list #2
\def\append@tok{\@ifstar\@append@tok\@append@tok@wrapped}
\def\@append@tok@wrapped#1#2{% wrapped in braces
  #2=\expandafter{\the#2{#1}}%
}%
\def\@append@tok#1#2{% as is
  #2=\expandafter{\the#2#1}%
}%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% iterate over a list, up to #1 many elements, adding empty ones if needed
\def\apply@macro@to@fixed@list#1#2#3#4{%
  % #1: exactly that many elements; add empty ones as needed,
  % #2: macro of one argument, #3: list delimiter, #4: list
  \begingroup%
  \def\next@el##1##2#3##3\@nil{%
    % ##1: "counter", ##2: next element, ##3: rest of list
    \append@tok{#2{##2}}\tmp@toks%
    \ifnum##1<#1\relax%
      \ifstrempty{##3}{%
        % call it with an empty element (delimiter)
        \expandafter\next@el\number\numexpr ##1+1\relax #3\@nil%
      }{%
        \expandafter\next@el\number\numexpr ##1+1\relax ##3\@nil%
      }%
    \fi%
  }%
  \tmp@toks={}%
  \next@el{1}#4#3\@nil%
  \expandafter\endgroup\the\tmp@toks%
}
% call a macro with the first #1 elements of list
% THIS DOES NOT WORK
\def\apply@macro@to@split@list@A#1#2#3#4{%
  % #1: exactly that many elements; add empty ones as needed,
  % #2: macro of #1 number of argument, #3: list delimiter, #4: list
  % for some reason this did not work... after exiting from \apply@macro@...
  % the token list was empty (but was correctly appended to inside \save@tok))
  \begingroup%
  \def\save@tok##1{%
    \append@tok{##1}\tmp@toks% does not append, simply reassigns
    % not really sure how to display the content without using \meaning and a buffer macro
    \expandafter\def\expandafter\@tmp\expandafter{\the\tmp@toks}%
    token list is \texttt{\meaning\@tmp}\par%
  }%
  % idea is to put the macro to be called at the front of the token list
  % then append its arguments; for debugging purposes, do not do that
%  \tmp@toks={#2}%
  \tmp@toks={}%
  \apply@macro@to@fixed@list{#1}\save@tok{#3}{#4}%
  exiting group, token list is \the\tmp@toks\par%
  % and execute the macro outside the group
%  \expandafter\endgroup\the\tmp@toks%
  \endgroup%
}
\def\apply@macro@to@split@list@B#1#2#3#4{%
  \begingroup%
  \def\save@tok##1{%
    \append@tok*{{##1}}\tmp@toks% does not append either, simply reassigns
    \expandafter\def\expandafter\@tmp\expandafter{\the\tmp@toks}
    token list is \texttt{\meaning\@tmp}\par%
  }%
  \tmp@toks={}%
  \apply@macro@to@fixed@list{#1}\save@tok{#3}{#4}%
  exiting group, token list is \the\tmp@toks\par%
  \endgroup%
}

\begin{document}
% to see that nested calls to \apply@macro@to@fixed@list work:
\def\foo#1{%
  % use a different delimiter
  \apply@macro@to@fixed@list{3}\bar:{#1a:#1b:#1c:#1d}%
}
\def\bar#1{element is: #1\par}
\apply@macro@to@fixed@list{3}\foo,{a,b,c,d}%
%
\def\foo#1#2{FOO: #1, #2;\par}
% using unstarred \@append@tok, i.e. wraps it in braces
\apply@macro@to@split@list@A{2}\foo:{a:}
% using starred \@append@tok, I wrap it in braces before passing it to \append@tok
\apply@macro@to@split@list@B{2}\foo:{a:}
% now I redefine \append@tok to be exactly the same as its starred version
\def\append@tok#1#2{% as is
  #2=\expandafter{\the#2#1}%
}%
% and pass it a wrapped token, as before
\def\apply@macro@to@split@list@C#1#2#3#4{%
  \begingroup%
  \def\save@tok##1{%
    \append@tok{{##1}}\tmp@toks%
    \expandafter\def\expandafter\@tmp\expandafter{\the\tmp@toks}
    token list is \texttt{\meaning\@tmp}\par%
  }%
  \tmp@toks={}%
  \apply@macro@to@fixed@list{#1}\save@tok{#3}{#4}%
  exiting group, token list is \the\tmp@toks\par%
  \endgroup%
}
% and it works
\apply@macro@to@split@list@C{2}\foo:{a:}
% it also works if I append the token without using a helper macro
\def\apply@macro@to@split@list@D#1#2#3#4{%
  \begingroup%
  \def\save@tok##1{%
    \tmp@toks=\expandafter{\the\tmp@toks {##1}}%
    \expandafter\def\expandafter\@tmp\expandafter{\the\tmp@toks}
    token list is \texttt{\meaning\@tmp}\par%
  }%
  \tmp@toks={}%
  \apply@macro@to@fixed@list{#1}\save@tok{#3}{#4}%
  exiting group, token list is \the\tmp@toks\par%
  \endgroup%
}
\apply@macro@to@split@list@D{2}\foo:{a:}
\end{document}

另外,我想知道我的一般方法和使用的技术是否合适?

答案1

这里,我引入了\feedtomama[]{},它以两种方式之一将参数传递给宏\mama。如果没有提供可选参数,则解析列表并将每个项目传递给\mama逐个传递给 。如果提供了可选参数,则将其视为项目数n在要传递给 的列表中\mama,一次一个。如果n小于列表长度,则仅将该数量的列表元素传递给\mama。如果n大于列表长度,则\mama列表耗尽后将传递空元素,直到传递的元素总数 =n

这里,\mama仅仅将其参数设置在括号中。

列表分隔符可以用, 默认逗号listofitems更改\setsepchar{},

\documentclass{article}
\usepackage{listofitems,pgffor}
\newcommand\feedtomama[2][\relax]{%
  \ifx\relax#1\feedalltomama{#2}\else\feedNtomama{#1}{#2}\fi%
}
\newcommand\feedalltomama[1]{%
  \readlist\z{#1}%
  \foreachitem\zz\in\z[]{\expandafter\mama\expandafter{\zz}}%
}
\newcommand\feedNtomama[2]{%
  \readlist\z{#2}%
  \foreach\zz in {1,...,#1}{%
    \ifnum\zz>\listlen\z[]\relax
      \mama{}%
    \else
      \expandafter\mama\expandafter{\zz}%
    \fi
  }
}
\newcommand\mama[1]{(#1)}
\begin{document}
\feedtomama{1,2,3,4,5}

\feedtomama[7]{1,2,3,4,5}

\feedtomama[3]{1,2,3,4,5}
\end{document}

在此处输入图片描述

相关内容