如何在序言中重新定义 \do 的情况下使用 etoolbox 中的 \dolistloop ?

如何在序言中重新定义 \do 的情况下使用 etoolbox 中的 \dolistloop ?

我尝试使用在序言中重新定义的 -command 来执行 from。但是,-command 的重新定义被\dolistloop忽略了。如果我将其放在文档中,它会按预期工作。以下是未按预期工作的示例:etoolbox\do\do

\documentclass{article}
\usepackage{etoolbox}

\newcommand{\alist}{}
\listadd{\alist}{Parrot}
\listadd{\alist}{Canary}

\def\birdlist{}

\renewcommand*{\do}[1]{
\appto\birdlist{Bird: #1. }
}

\begin{document}

\dolistloop{\alist}
\birdlist

\end{document}

该代码的输出为:ParrotCanary,表示\do尚未重新定义。如果我将重新定义\do移到文档中,

\documentclass{article}
\usepackage{etoolbox}

\newcommand{\alist}{}
\listadd{\alist}{Parrot}
\listadd{\alist}{Canary}

\def\birdlist{}

\begin{document}

\renewcommand*{\do}[1]{
\appto\birdlist{Bird: #1. }
}
\dolistloop{\alist}
\birdlist

\end{document}

结果是预期的:鸟:鹦鹉。鸟:金丝雀。如何将该\dolistloop函数与\do序言中定义的 -function 一起使用?(我正在处理一个包含多个子文件夹中的文档的项目,我想避免\renewcommand*{\do}在每个文件夹的 -files 中附加 -code .tex。)

答案1

我不建议\dolistloop在全局上下文中使用:\do是一个经常被重新定义的宏,尤其是在\begin{document}(或在\AtBeginDocument{...}中它获得的含义\noexpand。我也不想在里面“全局”地使用它\begin{document}

我建议使用\forlistloop需要处理程序的方法,但即使这样也可以简化(参见代码)

将个人定义重命名为\do ,比如,改为\dothis调用\forlistloop{\dothis}{\alist}

\documentclass{article}
\usepackage{etoolbox}

\newcommand{\alist}{}
\listadd{\alist}{Parrot}
\listadd{\alist}{Canary}

\newcommand{\birdlist}{}

\newcommand*{\dothis}[1]{%
\appto\birdlist{Bird: #1. }
}

%Define a wrapper
\newcommand{\fakedolistloop}[1]{%
  \forlistloop{\dothis}{#1}%
}

\fakedolistloop{\alist}

% Or call it directly

%\forlistloop{\dothis}{\alist}
\birdlist

\end{document}

在此处输入图片描述

不可避免的expl3解决方案

\documentclass{article}
\usepackage{etoolbox}

\usepackage{xparse}

\ExplSyntaxOn
\seq_new:N \g_rasmus_bird_seq

\NewDocumentCommand{\addbird}{+m}{
  \clist_map_inline:nn {#1} {
    \seq_gput_right:Nn \g_rasmus_bird_seq {##1}
  }
}

\NewDocumentCommand{\listloop}{}{
  \seq_map_inline:Nn \g_rasmus_bird_seq {\dothis{##1}}
}
\ExplSyntaxOff

\addbird{Parrot,Canary}
\addbird{Dead Parrot,Pantomime Goose}

\newcommand{\birdlist}{}

\newcommand*{\dothis}[1]{%
\appto\birdlist{Bird: #1. }
}

\begin{document}
\listloop


\birdlist
\end{document}

下一期

\documentclass{article}
\usepackage{etoolbox}

\newcommand{\alist}{}
\listadd{\alist}{Parrot}
\listadd{\alist}{Canary}

\newcommand{\birdlist}{}

\newcommand*{\dothis}[2]{%
  \appto{#1}{Bird: #2. }
}

\newcommand{\fakedolistloop}[2]{%
  \forlistloop{\dothis{#2}}{#1}%
}

\begin{document}
\newcommand{\otherbirdlist}{}
\fakedolistloop{\alist}{\birdlist}
\listadd{\alist}{Sparrow}

\fakedolistloop{\alist}{\otherbirdlist}

Showing:

\birdlist

or

\otherbirdlist
\end{document}

答案2

您不能\do那样使用。这是一个临时宏,您应该在使用时重新定义它,因为它的含义不可靠。

不同的实现:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\listadd}{mm}
 {
  \rasmus_list_add:nn { #1 } { #2 }
 }
\NewDocumentCommand{\listmap}{m+m}
 {
  % define the scratch macro based on the second argument
  \cs_set:Nn \__rasmus_list_do:n { #2 }
  % map the list using the newly defined macro
  \seq_map_function:cN { g_rasmus_list_#1_seq } \__rasmus_list_do:n
 }

\cs_new_protected:Nn \rasmus_list_add:nn
 {
  % make sure the list exists
  \seq_if_exist:cF { g_rasmus_list_#1_seq }
   {
    \seq_new:c  { g_rasmus_list_#1_seq }
   }
  % add the items
  \clist_map_inline:nn { #2 }
   {
    \seq_put_right:cn  { g_rasmus_list_#1_seq } { ##1 }
   }
 }
\ExplSyntaxOff

\begin{document}

\listadd{alist}{Parrot,Canary}

\listmap{alist}{%
  \listadd{birdlist}{Bird: #1.}%
}

\listmap{birdlist}{#1\par}

\end{document}

您可以按顺序添加项目,也可以以逗号分隔的列表添加,因此

\listadd{alist}{Parrot,Canary}

\listadd{alist}{Parrot}
\listadd{alist}{Canary}

是等效的。

如您所见,您可以将 用作\listmap不同的用途,这里用于填充新列表,这里用于打印新列表。列表中的当前项目简单地表示为#1

诀窍是在使用时自己重新定义临时宏。

在此处输入图片描述

相关内容