
Ich habe ein Makro erstellt, \joinlist
das Kommas oder andere Trennzeichen zwischen den Elementen einer etoolbox
internen Liste einfügt. Es hat eine spezielle Behandlung für Listen mit nur zwei Elementen („a und b“). Es weiß auch, wie man zwischen den letzten beiden Elementen längerer Listen („a, b und c“) ein anderes Trennzeichen einfügt. Hier ist die von mir erstellte Definition:
% 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}}
Speichern Sie das Obige unter join-list.sty
und betrachten Sie dann das folgende kleine Beispiel, das ein Problem zeigt:
\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
funktioniert gut zum Erstellen von Dokumenttextinhalten. Wir sehen wie erwartet „a“, dann „a und b“, dann „a, b und c“.
Leider \hypersetup{pdfauthor=...}
funktioniert die Verwendung dieses Makros nicht wie erhofft. Stattdessen werden die PDF-Autorenmetadaten des Dokuments auf "0 1110 1 , und a1 , und b1 , und c" gesetzt. Offensichtlich ist beim Erweitern/Auswerten des \joinlist
Makros in diesem Kontext etwas gründlich schiefgelaufen.
Was mache ich hier falsch? Wie kann ich das beheben? Gibt es andere Möglichkeiten, mein \joinlist
Makro zu verbessern? Gibt es bereits ein ähnliches Makro in einem weit verbreiteten Paket? (Ich habe gesucht, aber keines gefunden.)
Antwort1
Das Problem besteht darin, dass \joinlist
nicht „erweiterbar“ ist: Es muss Zuweisungen durchführen, wie \advance\@join@currentnum 1
sie im Wert von nicht möglich sind pdfauthor=
.
Mit expl3
(der nicht mehr ganz so experimentellen Programmierschicht für LaTeX3) haben Sie, was Sie brauchen.
\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}
Es gibt einige Änderungen in Bezug auf Ihre Einstellung. Listen haben einen Namen, anstatt durch ein Makro aufgerufen zu werden; eine neue kann durch erstellt werden \newlist
. Auch die Reihenfolge der Argumente \joinlist
ist anders:
- der Listenname;
- was sollte im Fall von zwei Elementen zwischen den Elementen stehen;
- was zwischen den Elementen stehen soll, wenn es mehr als zwei gibt (außer den letzten beiden);
- was soll zwischen denzuletztzwei Elemente, wenn mehr als zwei vorhanden sind.
Falls die Liste leer ist, wird nichts erzeugt, wenn sie nur ein Element enthält, wird dieses erzeugt.
Diese Version von \joinlist
ist erweiterbar und kann problemlos als Wert an übergeben werden pdfauthor=
.
Sie können den Code in der Präambel als Ersatz für Ihren Code in der .sty
Datei verwenden.