etoolbox
有没有一种简单的方法可以以特殊方式处理基于 的列表中的第一个和/或最后一个项目?这是一个简单的例子:
\documentclass{article}
\usepackage{etoolbox}
\begin{document}
\forcsvlist{\listadd\namelist}{Tom, Dick, Harry, Jack}
\renewcommand*{\do}[1]{; #1}
\dolistloop{\namelist}
\renewcommand*{\do}[1]{#1, }
\dolistloop{\namelist}
\end{document}
输出为
; 汤姆; 迪克; 哈利; 杰克
汤姆、迪克、哈利、杰克,
我将如何改变上述代码来创建输出
汤姆;迪克;哈利;杰克
汤姆、迪克、哈利和杰克
如果可以将第一项的格式定义为 简单 ,#1
而将其余项的格式定义为 ,则第一个输出将很容易实现。如果可以将除第一个项和最后一个项之外; #1
的所有项的格式定义为 ,则第二个输出将很容易实现。, #1
#1
and #1
请注意,我正在寻找etoolbox
列表的解决方案,而不是其他列表结构。
答案1
对于第一个问题,我会定义\do
在条目前面加上\process
,其初始含义只是将其自身重新定义为所需的分隔符:
\newcommand{\semicolonlist}[1]{%
\def\process{\def\process{; }}%
\def\do##1{\process##1}%
\dolistloop{#1}}
\semicolonlist\namelist
对于第二个问题,可以处理列表一次以获取元素的数量,然后在第二遍中使用该信息:
\newcommand{\commaorandlist}[1]{%
\count255=0
\def\do##1{\advance\count255 1 \chardef\finalitem=\count255 }%
\dolistloop{#1}%
\count255=0
\def\do##1{\advance\count255 1
\ifnum\count255=\finalitem
\space and\space
\else
\ifnum\count255=1
\else
,\space
\fi
\fi##1}
\dolistloop{#1}}
\commaorandlist\namelist
这些命令打印列表;如果您需要在可扩展的上下文中使用它们,您可以这样做,比如说\commaorandlist
,
\newcommand{\xcommaorandlist}[2]{%
\count255=0
\def\do##1{\advance\count255 1 \chardef\finalitem=\count255 }%
\dolistloop{#1}%
\count255=0
\toks0={}%
\def\do##1{\advance\count255 1
\edef\next{%
\ifnum\count255=\finalitem
\space and\space
\else
\ifnum\count255=1
\else
,\space
\fi
\fi
}
\toks2={##1}%
\edef\next{\the\toks0 \next \the\toks2}%
\toks0=\expandafter{\next}%
}%
\dolistloop{#1}%
\edef#2{\the\toks0 }%
}
然后调用
\xcommaorandlist\namelist\finallist
\hypersetup{pdfauthor={\finallist}}
答案2
这里有一个简单的解决方案,它也计算列表,并使用计数器来定位列表内的最后一个元素:
\documentclass{article}
\usepackage{etoolbox}
\begin{document}
\newcounter{elementcount}
\forcsvlist{\stepcounter{elementcount}\listadd\namelist}{Tom, Dick, Harry, Jack}
\number\value{elementcount}:
\def\do#1{%
\ifnumequal{\value{elementcount}}{1}{%
#1}{\addtocounter{elementcount}{-1}#1,~}%
}
\dolistloop{\namelist}
\end{document}