宏中的棘手扩展

宏中的棘手扩展

我写了下面的代码

\documentclass{article}
\makeatletter
 \newtoks\a@toks
 \newtoks\b@toks
 \newcounter{a@counter}%
 \newcounter{b@counter}%
 \setcounter{a@counter}{0}%
 \setcounter{b@counter}{0}%
 \newcommand{\aAdd}[1]{%
  \ifnum\thea@counter>0\a@toks=\expandafter{\the\a@toks {#1}}%
  \else\a@toks=\expandafter{\the\a@toks {#1}}%
  \fi
  \stepcounter{a@counter}%
 }
 \newcommand{\reset}{%
  \setcounter{a@counter}{0}%
  \a@toks={}%
 }
 \newcommand{\bexp}{%
  \ifnum\theb@counter>0\b@toks=\expandafter{\the\b@toks, (\the\a@toks)}%
  \else\b@toks=\expandafter{\the\b@toks (\the\a@toks) }%
  \fi
  \stepcounter{b@counter}%
  \setcounter{a@counter}{0}%
  \a@toks=\noexpand{}%
 }
 \newcommand{\print}{%
  \the\b@toks%
 }
\makeatother
\begin{document}
 Hello World!\\[3cm]
 \aAdd{a}
 \aAdd{b}
 \bexp
 \aAdd{c}
 \print
\end{document}

我想要做的事情如下:\aAdd我将一些元素添加到列表中,具体来说,在这个例子中

\aAdd{a}
\aAdd{b}

我期望\a@toks等于ab。然后我将其刷新到另一个标记中,因此我期望\b@toks等于ab。问题是当命令

\a@toks={}

执行后,即使\b@toks继续跟随 \a@toks,这样,当我执行

\aAdd{c}

\b@toks具有价值c

我想,一旦设置\b@toks = \a@toks为仅设置的值\b@toks,这样,当我重新定义时\a@toks\b@toks继续具有前面的值(在本例中ab)。

谁能帮我?

答案1

\expandafter不扩大一切之后,只需添加以下标记。此外,由于它似乎b@counter衡量了添加到的内容\b@toks,因此我认为没有必要

\ifnum...
\else\b@toks=\expandafter{\the\b@toks (\the\a@toks) }
\fi

您想要\b@toks在其中添加(一个空的)内容。

我认为以下内容会产生您想要的结果(我对其进行了一些清理):

在此处输入图片描述

\documentclass{article}

\makeatletter
\newtoks\a@toks
\newtoks\b@toks
\newcounter{b@counter}%
\newcounter{a@counter}[b@counter]%

\newcommand{\aAdd}[1]{%
  \ifnum\value{a@counter}>0 \a@toks=\expandafter{\the\a@toks {#1}}%
  \else\a@toks=\expandafter{\the\a@toks {#1}}%
  \fi
  \stepcounter{a@counter}%
}
\newcommand{\reset}{%
  \setcounter{a@counter}{0}%
  \a@toks={}%
}
\newcommand{\bexp}{%
  \ifnum\value{b@counter}>0
    \edef\x{\noexpand\b@toks={\the\b@toks, (\the\a@toks)}}%
  \else
    \edef\x{\noexpand\b@toks={(\the\a@toks)}}%
  \fi
  \x
  \stepcounter{b@counter}%
  \a@toks={}%
}
\newcommand{\print}{%
  \the\b@toks%
}
\makeatother

\begin{document}

Hello World!

\bigskip

\aAdd{a}% \a@toks = {a}
\aAdd{b}% \a@toks = {a}{b}
\bexp% \a@toks = {}, \b@toks = {a}{b}
\aAdd{c}% \a@toks = {c}
\print% \b@toks

\end{document}

可以使用

\b@toks=\expandafter{\expandafter(\the\a@toks)}

确保\a@toks在将其插入之前已展开\b@toks。但是,我选择\b@toks使用一种\edef\x{...}\x方法确保在将其添加到之前所有内容都已展开。

如果留下不想要的东西\x是一个问题,您可以使用以下定义\bexp

\newcommand{\bexp}{%
  \begingroup
  \ifnum\value{b@counter}>0
    \edef\x{\endgroup\noexpand\b@toks={\the\b@toks, (\the\a@toks)}}%
  \else
    \edef\x{\endgroup\noexpand\b@toks={(\the\a@toks)}}%
  \fi
  \x
  \stepcounter{b@counter}%
  \a@toks={}%
}

答案2

Werner 的分析非常好。下面是使用 和 的替代实现xparseexpl3请注意,您可以将项之间的分隔符定义为可选参数\print(默认为“逗号空格”)。

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\aAdd}{m}
 {
  \mapo_aadd:n { #1 }
 }
\NewDocumentCommand{\bexp}{}
 {
  \mapo_bexp:
 }
\NewDocumentCommand{\reset}{}
 {
  \mapo_reset:
 }
\NewDocumentCommand{\print}{O{,~}}
 {
  \mapo_print:n { #1 }
 }

\tl_new:N \l_mapo_a_tl
\seq_new:N \l_mapo_b_seq

\cs_new_protected:Nn \mapo_aadd:n
 {
  \tl_put_right:Nn \l_mapo_a_tl { #1 }
 }
\cs_new_protected:Nn \mapo_bexp:
 {
  \seq_put_right:Nx \l_mapo_b_seq { ( \exp_not:V \l_mapo_a_tl ) }
  \mapo_reset:
 }
\cs_new_protected:Nn \mapo_reset:
 {
  \tl_clear:N \l_mapo_a_tl
 }
\cs_new:Nn \mapo_print:n
 {
  \seq_use:Nn \l_mapo_b_seq { #1 }
 }
\ExplSyntaxOff

\begin{document}

\noindent
Hello World!\\
\aAdd{a}\aAdd{b}\bexp\aAdd{c}%
\print\\
\bexp
\print[---]

\end{document}

在此处输入图片描述

相关内容