
Ich habe mich über die verschiedenen verfügbaren Methoden zum Durchlaufen einer durch Kommas getrennten Liste und dergleichen gewundert. Insbesondere habe ich mich über ihre verschiedenen Stärken und Schwächen gewundert. Mit anderen Worten, ich habe mich über Dinge wie Folgendes gewundert (aber nicht nur auf diese Liste beschränkt):
- ob sie erweiterbar sind oder nicht,
- wie sie mit Leergut umgehen,
- wie mit überflüssigen Leerzeichen am Anfang und Ende umgegangen wird
\def
ob Sie / verwenden können\edef
oder müssen,\gdef
um\xdef
Informationen innerhalb der Schleife für die spätere Verwendung zu speichern.
Hier ist eine Liste der mir bekannten Schleifenmethoden, ohne bestimmte Reihenfolge. In der folgenden Liste \current@item
ist ein Makro mit einem Argument dargestellt, um das aktuelle Element in der Iteration zu formatieren.
Verwenden von Befehlen aus 2ekernal
:
%% \@for
\def\@for@myloop#1{%%
\@for \x:=#1 \do{\current@item \x}}
%% \@tfor (not a comma separated list--probably shouldn't be here)
\def\@tfor@myloop#1{%%
\@tfor \x:=#1 \do{\if,\x\relax\else\current@item \x\fi}}
etoolbox
Paket verwenden
%% `etoolbox`: need to be careful whether passed a macro:
%% in that case expansion may be necessary to that the
%% delimiters are visible to `\forcsvlist`
\def\etoolbox@myloop#1{%%
\expandafter\forcsvlist
\expandafter\current@item
\expandafter{#1}}
pgffor
Paket verwenden
%% pgffor
\def\pgffor@myloop#1{%%
\foreach \x in {#1} {\current@item \x}}
Eine Homebrew-Methode:
%% version a la `ae`
\def\@ae@myloop#1,#2\@nil{%%
\current@item{#1}%%
\expandafter\ifx\expandafter\relax\detokenize{#2}\relax\else
\@ae@myloop#2\@nil
\fi
}
\def\ae@myloop#1{%%
\@ae@myloop#1,\@nil
}
Dann gibt es auch noch die verschiedenen expl3
Methoden wie (davon gibt es ziemlich viele, diese Liste ist also kaum erschöpfend):
\tl_map_inline:nn
\tl_map_function:Nn
\clist_map_inline:Nn
\seq_map_inline:Nn
Hier ist ein MWE, das die Ergebnisse von jedem davon veranschaulicht (einschließlich einer LaTeX3-Version):
\documentclass{article}
\usepackage[margin=0.5in,paperheight=15in]{geometry}
\usepackage{xparse}
\usepackage{etoolbox}
\usepackage{pgffor}
\usepackage{enumitem}
\makeatletter
\def\my@item@count{0}
\def\step@my@counter{\xdef\my@item@count{\number\numexpr\my@item@count+1\relax}}
%% \rules to emphasize how spaces are seen and treated!
\def\current@item#1{\step@my@counter\item \rule{0.4pt}{2ex}#1\rule{0.4pt}{2ex}}
%% `etoolbox`
\def\etoolbox@myloop#1{%%
\forcsvlist \current@item {#1}}
%% but if passed a macro, then it first needs to be expanded so the delimiters are visible to `\forcsvlist`. You'll need to write
%% \expandafter\forcsvlist \expandafter\current@item \expandafter{#1}}
%% \@for
\def\@for@myloop#1{%%
\@for \x:=#1 \do{\current@item \x}}
%% \@tfor
\def\@tfor@myloop#1{%%
\@tfor \x:=#1 \do{\current@item \x}}
%% pgffor
\def\pgffor@myloop#1{%%
\foreach \x in {#1} {\current@item \x}}
%% version a la `ae`
\def\@ae@myloop#1,#2\@nil{%%
\current@item{#1}%%
\expandafter\ifx\expandafter\relax\detokenize{#2}\relax\else
\@ae@myloop#2\@nil
\fi
}
\def\ae@myloop#1{%%
\@ae@myloop#1,\@nil
}
\def\listoffruit#1#2#3{%%
\def\my@item@count{0}%%
\noindent
List of type \texttt{#1}: \parbox[t]{3in}{\raggedright#3}
\begin{itemize}[topsep=4pt,itemsep=2pt]
\csname#1@myloop\endcsname{#2}%%
\end{itemize}
Total number of bulleted items: \my@item@count
\par \vspace{2ex}\hrule\par \vspace{2ex}
}
\ExplSyntaxOn
\NewDocumentCommand{\expl@myloop}{ m }
{
\clist_map_inline:nn{#1}{\current@item {##1}}
}
\ExplSyntaxOff
\makeatother
\def\apples{apples}
\def\bananas{bananas}
\def\cherries{cherries}
\begin{document}
\listoffruit{etoolbox}{apples,, oranges, bananas ,cherries}{Ignores leading spaces and empty items. Trailing spaces not ignored.}
\listoffruit{@for}{apples,, oranges, bananas ,cherries}{Empty lines and trailing or leading spaces not ignored. Something goes on with last item in list.}
\listoffruit{@tfor}{\apples,{} {oranges}\bananas\cherries}{Spaces ignored, all other token respected, bracketed tokens treated as one.}
\listoffruit{pgffor}{apples,, oranges, bananas ,cherries}{Ignores leading spaces, empty items and trailing spaces not ignored.}
\listoffruit{ae}{apples,, oranges, bananas ,cherries}{Leading or trailing spaces not ignored. Empty items not ignored.}
\listoffruit{expl}{apples,, oranges, bananas ,cherries}{Trailing or leading spaces ignored. Empty items ignored.}
\end{document}
Mir bekannte Probleme:
- Ich glaube,
\@for
es ist nicht erweiterbar, \cslist_map_inline:nn
ist erweiterbar, jedoch mit Einschränkungen: d. h., es ist in einem Argument vom Typ - nicht erweiterbarf
.pgffor
Die\foreach
Schleife wird innerhalb einer Gruppe ausgeführt. Sie müssen also Informationen aus der Gruppe für die spätere Verwendung speichern\gdef
oder verwenden. Ich habe noch nicht vollständig untersucht, welche anderen der hier vorgestellten Schleifen eine ähnliche\xdeg
Mangel(nicht sicher, ob das die richtige Wortwahl ist). Ich habe keine Ahnung, ob\foreach
es erweiterbar ist oder nicht.- Einige Methoden handhaben ihre Listen recht gut, egal ob sie explizit oder implizit über ein Makro übergeben werden. Beispielsweise weiß
pgffor
's\foreach
, was mit einer über ein Makro übergebenen Liste zu tun ist.etoolbox
's\forcsvlist
erfordert, dass dieses Makro zuerst erweitert wird: daher ist meine erste Abbildung von a\forcslist
so kompliziert, wie sie ist.
Was mich hier interessiert ist:
- Antworten, die auf die Stärken und Schwächen der verschiedenen hier vorgestellten Ansätze eingehen, wie am Anfang dieses Beitrags aufgelistet, aber nicht unbedingt auf diese Vorschläge beschränkt, da mir andere wichtige Punkte möglicherweise nicht bewusst sind. Ich bin mir beispielsweise nicht wirklich sicher, welche erweiterbar sind.
- Antworten, die andere Methoden zum Durchlaufen einer Liste von Elementen sowie deren bekannte Schwächen und Stärken vorstellen.
- Antworten, die realistische Beispiele veranschaulichen können, für die man eine solche Schleife in einem erweiterbaren Kontext verwenden möchte
- Antworten, die veranschaulichen, wie man innerhalb der Gruppe gesammelte Informationen für die spätere Verwendung speichern kann.
Antwort1
Ich schlage eine andere Definition vor von\current@item
\def\current@item#1{%
\stepcounter{item@count}
\item $|$#1$|$\ $|$\texttt{\detokenize{#1}}$|$%
}
Die Ausgabe zeigt also auch, was wirklich als Argument übergeben wird. Außerdem habe ich die komplizierte Verwaltung von \my@item@count
durch einen einfachen Zähler ersetzt. Ich kommentiere nichts zu \@tfor
, da es sich um ein anderes Tool handelt, das nicht für durch Kommas getrennte Listen entwickelt wurde.
etoolbox
:\forcsvlist
entfernt keine nachstehenden Leerzeichen; Ihre Definition ist zu kompliziert, weil%% `etoolbox` \def\etoolbox@myloop#1{%% \forcsvlist\current@item{#1}}
reicht aus. Elemente werden explizit übergeben.
\@for
ist das grundlegende Werkzeug, das im LaTeX-Kernel definiert ist. Führende und nachfolgende Leerzeichen werden nicht entfernt. Elemente werden als übergeben\x
, die Steuersequenz, die nach verwendet wird\@for
.\foreach
entfernt keine nachstehenden Leerzeichen. Elemente werden als übergeben\x
, die Steuersequenz, die nach verwendet wird\foreach
.ae
ist grundsätzlich wie\@for
, funktioniert aber durch Erweiterung. Führende und nachfolgende Leerzeichen werden nicht entfernt. Elemente werden explizit übergeben.expl
entfernt führende und nachfolgende Leerzeichen, aber auch leere Elemente; Elemente werden explizit übergeben.
\documentclass{article}
\usepackage[margin=0.5in,paperheight=15in]{geometry}
\usepackage{xparse}
\usepackage{etoolbox}
\usepackage{pgffor}
\usepackage{enumitem}
\makeatletter
\newcounter{item@count}
%% \rules to emphasize how spaces are seen and treated!
\def\current@item#1{%
\stepcounter{item@count}
\item $|$#1$|$\ $|$\texttt{\detokenize{#1}}$|$%
}
%% `etoolbox`
\def\etoolbox@myloop#1{%%
\forcsvlist\current@item{#1}}
%% \@for
\def\@for@myloop#1{%%
\@for \x:=#1\do{\current@item \x}}
%% pgffor
\def\pgffor@myloop#1{%%
\foreach \x in {#1} {\typeout{pgf:\x}\current@item \x}}
%% version a la `ae`
\def\@ae@myloop#1,#2\@nil{%%
\current@item{#1}%%
\if\relax\detokenize{#2}\relax\else
\@ae@myloop#2\@nil
\fi
}
\def\ae@myloop#1{%%
\@ae@myloop#1,\@nil
}
\def\listoffruit#1#2{%%
\setcounter{item@count}{0}%%
\noindent
List of type \texttt{#1}
\begin{itemize}[topsep=4pt,itemsep=2pt]
\csname#1@myloop\endcsname{#2}%%
\end{itemize}
Total number of bulleted items: \arabic{item@count}%
\par \vspace{2ex}\hrule\par \vspace{2ex}
}
\ExplSyntaxOn
\NewDocumentCommand{\expl@myloop}{ m }
{
\clist_map_inline:nn{#1}{\current@item {##1}}
}
\ExplSyntaxOff
\makeatother
\begin{document}
\listoffruit{etoolbox}{apples,, oranges, bananas ,cherries}
\listoffruit{@for}{apples,, oranges, bananas ,cherries}
\listoffruit{pgffor}{apples,, oranges, bananas ,cherries}
\listoffruit{ae}{apples,, oranges, bananas ,cherries}
\listoffruit{expl}{apples,, oranges, bananas ,cherries}
\end{document}
Ich würde eine weitere Schleife hinzufügen expl3
, die auch leere Elemente berücksichtigt:
\ExplSyntaxOn
\NewDocumentCommand{\seq@myloop}{ m }
{
\seq_set_split:Nnn \l_tmpa_seq { , } { #1 }
\seq_map_inline:Nn \l_tmpa_seq { \current@item {##1} }
}
\ExplSyntaxOff
(von der Verwendung wird natürlich \l_tmpa_seq
abgeraten. Es ist besser, eine neue Variable zuzuweisen.)
Der Vergleich sollte keinen Zweifel lassen. Der einzige Punkt, in dem \foreach
es überlegen ist, ist die Behandlung von „unvollständigen Listen“, wie z. B. 1,2,...,20
.
Antwort2
LuaLaTeX:
\documentclass{standalone}
\usepackage{tikz}
\usepackage{filecontents}
\begin{document}
\newcommand{\drawCircle}[1]{\tikz \draw (0,0) circle (#1);}
\begin{filecontents*}{testlua.lua}
for i=1,10 do
tex.print("\\drawCircle{",0.1*i,"}")
end
\end{filecontents*}
\directlua{dofile('testlua.lua')}
\end{document}