我尝试使用在序言中重新定义的 -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
。
诀窍是在使用时自己重新定义临时宏。