Вэта почта, я нашел хороший трюк для работы со списками. Код ниже позволяет печатать списки с необязательным аргументом-разделителем.
\documentclass{article}
\usepackage{etoolbox}% http://ctan.org/pkg/etoolbox
\newcommand{\printlist}[2][,]{%
\def\itemdelim{\def\itemdelim{#1}}% Item delimiter delayed by one cycle
\renewcommand*{\do}[1]{\itemdelim##1}% How each item is processed
\docsvlist{#2}}% Process CSV list
\begin{document}
$\printlist{1,2,3,4,5,6,7}$ \par
$\printlist[;]{a,b,c,d,e,f}$
\end{document}
Однако, если я использую \printlist
в \author
команде в сочетании с новой строкой \\
, это не будет работать правильно: перенос строки устанавливается только для первого элемента списка. Для всех остальных элементов перенос строки игнорируется:
\documentclass{article}
\usepackage{etoolbox}% http://ctan.org/pkg/etoolbox
\newcommand{\printlist}[2][;]{%
\def\itemdelim{\def\itemdelim{#1}}% Item delimiter delayed by one cycle
\renewcommand*{\do}[1]{\itemdelim##1}% How each item is processed
\docsvlist{#2}}% Process CSV list
\title{Test}
\author{\printlist[,\\]{abc,def,ghi,jkl}}
\begin{document}
\maketitle
\end{document}
Если я использую разделитель без переноса строки, например ::
, то приведенный выше код работает так, как и ожидалось.
Добавление дополнительных переносов строк \\
в \author
команду также приводит к ожидаемому результату:
\author{\printlisti[::]{abc,def,ghi}\\123\\456\\789}
Кажется, что сочетание \printlist
с переносами строк \\
вызывает проблему. Почему?
решение1
Аргумент \author
будет набран в tabular
. Каждая ячейка образует свою собственную группу, таким образом, внутреннее определение \itemdelim
и определение \do
не сохранятся в первой строке.
По сути, вот что происходит:
\begin{tabular}{c}
\def\itemdelim{test} \\
\itemdelim
\end{tabular}
и то же самое для \do
, хотя во второй строке это будет иметь то же определение, что и за пределами tabular
и не приведет к сообщению об ошибке.
Вам нужно будет сделать определения \itemdelim
(для не первой записи) и \do
глобальные:
\newcommand{\printlist}[2][;]{%
\def\itemdelim{\gdef\itemdelim{#1}}%
\gdef\do##1{\itemdelim##1}%
\docsvlist{#2}}
\author{\printlist[,\\]{abc,def,ghi,jkl}}
Хотя вы можете применить «трюк» \itemdelim
напрямую for \do
и пропустить, \itemdelim
используя #1
напрямую:
\newcommand{\printlist}[2][;]{%
\def\do##1{##1\gdef\do####1{#1####1}}%
\docsvlist{#2}}
\author{\printlist[,\\]{abc,def,ghi,jkl}}
С помощью другого вспомогательного макроса, например, \defdo
мы можем избежать определения \do
глобального макроса (за счет другого макроса, определенного на уровне документа):
\newcommand*\defdo[1]{%
\def\do##1{#1\defdo{#1}##1}}%
\newcommand{\printlist}[2][;]{%
\def\do##1{##1\defdo{#1}}%
\docsvlist{#2}}%
\author{\printlist[,\\]{abc,def,ghi,jkl}}
Это переносит определение \do
из строки в строку за \\
так, чтобы оно было доступно в следующей строке.
В качестве альтернативы вы можете предварительно обработать список и просто переслать его по адресу \author
:
\newcommand{\savelist}[3][;]{%
\renewcommand*\do[1]{%
\newcommand*#3{##1}%
\renewcommand*\do[1]{%
\appto#3{#1####1}%
}%
}%
\docsvlist{#2}}
\savelist[,\\]{abc,def,ghi,jkl}\authors
\author{\authors}
В этом случае определение \do
также является «глобальным», поскольку оно определено на верхнем уровне документа.
Определение \do
global не должно создавать конфликта, поскольку любой другой код, который его использует, \do
должен был определить его сам, не предполагая никакого определения. Смешивание глобальных и локальных назначений/определенийможет быть грязно, поэтому использование \savelist
может быть предпочтительнее.
Заглядывая дальше etoolbox
, пакет LaTeX3 l3clist
предоставляет \clist_use:Nn
, которому не нужны никакие определения, чтобы просто поместить что-то ( #1
= ,\\
) между записями списка:
\documentclass{article}
\ExplSyntaxOn
\DeclareDocumentCommand{\printlist}{ O{;} m}{
\clist_set:Nn \l_tmpa_clist {#2}
\clist_use:Nn \l_tmpa_clist {#1}
}
\ExplSyntaxOff
\author{\printlist[,\\]{abc,def,ghi,jkl}}
\title{Test}
\begin{document}
\maketitle
\end{document}