为数组赋值时扩展命令

为数组赋值时扩展命令

我将通过一个例子来解释我的意思。

\documentclass{article}
\usepackage{arrayjobx}
\newcounter{foo}
\setcounter{foo}{0}
\renewcommand{\bar}{\addtocounter{foo}{1}Some text}
\newarray\baz
% -------------------
\begin{document}
\baz(1)={\bar}
\arabic{foo} % foo should be 1

\baz(1), \arabic{foo} % foo should still be 1

\baz(1), \arabic{foo} % foo should once again be 1
\end{document}

当我将命令分配\bar给数组时,它不会扩展,而是原封不动地分配给数组,这意味着计数器foo保持为零,直到我调用\baz(1)

是否可以使其\bar在分配给数组时立即扩展\baz,以便计数器只增加一次,并且的值\baz(1)仅仅等于Some text

答案1

下面添加了两个宏\addtoarraywithcounter\addtoarrayasbox。前者可以处理\addtocounter参数中的无括号(如果参数只有一个标记,例如单个宏,则在处理之前将参数展开一次)。

后者非常短(8 行代码)。它可以处理几乎任意的宏内容,并且只将排版结果包含在数组中。它通过在框内排版参数并将框存储在数组内来实现这一点。不在全局范围内起作用的代码不会对排版框之外产生任何影响(在下面的示例中,我在 的定义\def\baz{hihi}中添加了\bar,以表明这不会改变 的定义\baz)。然而,LaTeX\addtocounter全局设置计数器,因此它会影响 第三个参数之外的代码\addtoarrayasbox

\documentclass{article}
\usepackage{arrayjobx}
\newcounter{foo}
\setcounter{foo}{0}
\renewcommand{\bar}{\addtocounter{foo}{1}Some text\def\baz{hihi}}
\newarray\baz
% -------------------

\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand \addtoarraywithcounter { m m +m }
  {
    % if only one token is handed in and that is not a space
    \bool_if:nTF
      { \tl_if_single_token_p:n { #3 } && \tl_if_head_is_N_type_p:n { #3 } }
      {
        % expand that token, it might be a macro
        \noibe_array_with_counter:nno { #1 } { #2 } { #3 }
      }
      {
        % seems to be a more than a single token
        \noibe_array_with_counter:nnn { #1 } { #2 } { #3 }
      }
  }
\cs_new_protected:Npn \noibe_array_with_counter:nnn #1 #2 #3
  {
    \tl_if_in:nnTF { #3 } { \addtocounter }
      {
        \noibe_handle_addtocounter:nnw { #1 } { #2 } \q_nil #3 \q_stop
      }
      {
        \noibe_add_to_array:nnn { #1 } { #2 } { #3 }
      }
  }
\cs_new_protected:Npn
  \noibe_handle_addtocounter:nnw #1 #2 #3 \addtocounter #4 #5
  {
    \addtocounter { #4 } { #5 }
    \noibe_handle_addtocounter_auxi:nnow { #1 } { #2 } { \use_none:n #3 } \q_nil
  }
\cs_new_protected:Npn \noibe_handle_addtocounter_auxi:nnnw #1 #2 #3 #4 \q_stop
  {
    \noibe_handle_addtocounter_auxii:nnno
      { #1 } { #2 } { #3 } { \use_none:n #4 }
  }
\cs_generate_variant:Nn \noibe_handle_addtocounter_auxi:nnnw { nnow }
\cs_new_protected:Npn \noibe_handle_addtocounter_auxii:nnnn #1 #2 #3 #4
  {
    \noibe_add_to_array:nnn { #1 } { #2 } { #3 #4 }
  }
\cs_generate_variant:Nn \noibe_handle_addtocounter_auxii:nnnn { nnno }
\cs_new_protected:Npn \noibe_add_to_array:nnn #1 #2 #3
  {
    #1 ( #2 ) = { #3 }
  }
\cs_generate_variant:Nn \noibe_array_with_counter:nnn { nno }
\NewDocumentCommand \addtoarrayasbox { m m m }
  {
    \cs_if_exist:cF { l__noibe_array_ \cs_to_str:N #1 _content_ #2 _box }
      { \box_new:c { l__noibe_array_ cs_to_str:N _content_ #2 _box } }
    \hbox_set:cn { l__noibe_array_ cs_to_str:N _content_ #2 _box } { #3 }
    #1 ( #2 ) = 
      { \hbox_unpack:c { l__noibe_array_ cs_to_str:N _content_ #2 _box } }
  }
\ExplSyntaxOff


\begin{document}
\addtoarrayasbox\baz{1}{\bar}
\addtoarraywithcounter\baz{2}{{hihi}\addtocounter{foo}{1}{haha}}
%\baz(1)={\bar}
\arabic{foo} % foo should be 2

\baz(1), \baz(2), \arabic{foo} % foo should still be 2

\baz(1), \baz(2), \arabic{foo} % foo should once again be 2
\end{document}

在此处输入图片描述

相关内容