
\joinlist
内部リストの要素間にコンマやその他の区切り文字を追加するマクロ を作成しましたetoolbox
。このマクロは、2 つの要素 ("a と b") だけからなるリストに対して特別な処理を行います。また、長いリストの最後の 2 つの項目 ("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」が表示されます。
残念ながら、これを で使用しても期待どおりには動作しません。代わりに、ドキュメントの PDF 作成者メタデータが「0 1110 1 、および a1 、および b1 、および c」に設定されます。明らかに、このコンテキストでのマクロの\hypersetup{pdfauthor=...}
展開/評価で何か大きな問題が発生しています。\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
異なります。
- リスト名。
- 要素が 2 つある場合、要素間に何を配置するか。
- 要素が 2 つ以上ある場合 (最後の 2 つを除く)、要素の間に何を配置するか。
- 間に何を置くべきか最後要素が 2 つ以上ある場合は 2 つ。
リストが空の場合は何も生成されません。要素が 1 つしかない場合は、その要素が生成されます。
このバージョンの は\joinlist
拡張可能であり、 に値として指定しても問題はありませんpdfauthor=
。
プリアンブル内のコードを、.sty
ファイル内のドロップ置換として使用できます。