如果 \author 處理另一個命令的輸出,則它會缺少換行符

如果 \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
\begin{document}
$\printlist{1,2,3,4,5,6,7}$ \par
$\printlist[;]{a,b,c,d,e,f}$
\end{document}

但是,如果我\printlist\author命令中與 newline 結合使用\\,則這將無法正常工作:僅為列表的第一個元素設定換行符。對於所有其他元素,換行符號將被忽略:

\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}

失敗案例

如果我使用不含換行符的分隔符,例如::,則以上內容按預期工作。

測試成功1

\\在命令中加入額外的換行符號\author也會產生預期的結果:

\author{\printlisti[::]{abc,def,ghi}\\123\\456\\789}

測試成功2

看來\printlist與換行符的組合\\引起了問題。怎麼會?

答案1

的參數\author將被排版在tabular.每個單元格形成自己的群組,因此, 的內部定義\itemdelim和 的定義\do將無法在第一行中保留下來。

本質上,這就是正在發生的事情:

\begin{tabular}{c}
  \def\itemdelim{test} \\
  \itemdelim
\end{tabular}

和 for 相同\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}}

不過,您可以直接套用「技巧」\itemdelimfor\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這會將from row的定義隱藏在 the 後面\\,以便它在下一行中可用。


或者,您可以預處理清單並將其轉發到\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也是「全域」的,因為它是在文件的頂層定義的。

定義\doglobal 不應產生衝突,因為使用的所有其他程式碼都\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}

相關內容