
我創建了一個宏,\joinlist
它在內部列表的元素之間添加逗號或其他分隔符號etoolbox
。它對僅包含兩個元素(“a 和 b”)的清單進行特殊處理。它也知道如何在較長列表的最後兩項(“a、b 和 c”)之間放置不同的分隔符號。這是我創建的定義:
% typical use: \joinlist{\listmacro}{, }{, and }{ and }
\RequirePackage{etoolbox}
\newcommand{\@join@ignore}[1]{} % used to ignore current list element when counting
\newcount\@join@listlength % used to count length of list
\newcount\@join@currentnum % used to track current list element number
\newcommand{\joinlist}[4]{%
%
% count list elements
\@join@listlength 0 %
\forlistloop{\advance\@join@listlength 1\relax\@join@ignore}{#1}%
%
% now join list elements, tracking current element number
\@join@currentnum 0 %
\forlistloop{%
\advance\@join@currentnum 1 %
\ifnumequal{\the\@join@currentnum}{1}%
{}% first
{% not first
\ifnumequal{\the\@join@currentnum}{\the\@join@listlength}%
{% last
\ifnumequal{\the\@join@listlength}{2}%
{#4}% last of exactly two
{#3}% last of more than two
}%
{#2}% neither first nor last
}%
}%
{#1}}
將以上內容儲存為join-list.sty
,然後考慮以下顯示問題的小範例:
\documentclass{article}
\usepackage{hyperref}
\usepackage{join-list}
\begin{document}
\newcommand{\people}[0]{}
\listadd{\people}{a}
\joinlist{\people}{, }{, and }{ and } % a
\listadd{\people}{b}
\joinlist{\people}{, }{, and }{ and } % a and b
\listadd{\people}{c}
\joinlist{\people}{, }{, and }{ and } % a, b, and c
\hypersetup{pdfauthor=\joinlist{\people}{, }{, and }{ and }}
\end{document}
\joinlist
非常適合建立文件正文內容。正如預期的那樣,我們看到“a”,然後是“a 和 b”,然後是“a、b 和 c”。
不幸的是,使用它\hypersetup{pdfauthor=...}
並沒有像希望的那樣工作。相反,它將文件的 PDF 作者元資料設定為「0 1110 1 、 a1 、 b1 、 c」。顯然,\joinlist
在這種情況下擴展/評估巨集出現了嚴重錯誤。
我在這裡做錯了什麼?我怎樣才能解決這個問題?有其他方法\joinlist
可以改進我的巨集嗎?某些廣泛可用的軟體包中是否已經存在類似的巨集? (我搜尋過,但沒有找到。)
答案1
問題是它\joinlist
不是「可擴展的」:它必須執行諸如\advance\@join@currentnum 1
不能在 的值中完成的賦值pdfauthor=
。
有了expl3
(LaTeX3 不再是實驗性的程式設計層),就有了您所需要的。
\documentclass{article}
\usepackage{hyperref}
\RequirePackage{xparse}
\ExplSyntaxOn
\DeclareExpandableDocumentCommand{\joinlist}{ m m m m }
{
\seq_use:cnnn { g_liblit_list_#1_seq } { #2 } { #3 } { #4 }
}
\cs_generate_variant:Nn \seq_use:Nnnn { c }
\NewDocumentCommand{\newlist}{ m }
{
\seq_new:c { g_liblit_list_#1_seq }
}
\NewDocumentCommand{\listadd}{ m m }
{
\seq_gput_right:cn { g_liblit_list_#1_seq } { #2 }
}
\ExplSyntaxOff
\begin{document}
\newlist{people}
\listadd{people}{a}
\joinlist{people}{ and }{, }{, and } % a
\listadd{people}{b}
\joinlist{people}{ and }{, }{, and } % a and b
\listadd{people}{c}
\joinlist{people}{ and }{, }{, and } % a, b, and c
\hypersetup{pdfauthor=\joinlist{people}{ and }{, }{, and }}
\end{document}
您的設定有一些變化。列表有一個名稱,而不是由巨集呼叫;可以創建一個新的\newlist
。參數的順序也\joinlist
不同:
- 列表名稱;
- 如果有兩個元素,元素之間應該放什麼;
- 當元素超過兩個時(最後兩個除外),元素之間應該放什麼;
- 之間該走什麼最後的當有兩個以上的元素時,兩個元素。
如果清單為空,則不會產生任何內容;只有一種元素,就會產生該元素。
這個版本的\joinlist
是可擴展的,將其作為值賦予 是沒有問題的pdfauthor=
。
您可以使用序言中的程式碼來替換.sty
檔案中您的程式碼。