
私は、カンマ区切りのリストなどをループ処理するために利用できるさまざまな方法について考えていました。特に、それらのさまざまな長所と短所について考えていました。言い換えると、次のようなことについて考えていました (ただし、このリストに限定されるわけではありません)。
- 拡張可能かどうか
- 空のアイテムをどのように処理するか、
- 余分な先頭と末尾のスペースをどのように処理するか
- ループ内の情報を後で使用するために保存するために
\def
/ を使用できるかどうか、または/\edef
を使用する必要があるかどうか。\gdef
\xdef
順不同ですが、私がよく知っているループ メソッドのリストを以下に示します。次のリストは、\current@item
反復処理で現在の項目をフォーマットするための、1 つの引数を取るマクロを表しています。
からのコマンドの使用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
パッケージの使用
%% `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
パッケージの使用
%% 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
}
さらに、次のようなさまざまな方法もありますexpl3
(非常に多くの方法があるため、すべてを網羅することはできません)。
\tl_map_inline:nn
\tl_map_function:Nn
\clist_map_inline:Nn
\seq_map_inline:Nn
以下に、それぞれの結果を示す MWE を示します (LaTeX3 バージョンも 1 つ含む)。
\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}
私が認識している問題:
\@for
拡張できないと思いますが、\cslist_map_inline:nn
拡張可能ですが、制限があります。つまり、 -type 引数では拡張できませんf
。pgffor
の\foreach
ループはグループ内で実行されます。そのため、グループ内の情報を後で使用するために保存するに\gdef
は、またはを使用する必要があります\xdeg
。ここで紹介した他のループのどれが同様の機能を持つかは、まだ十分に調査していません。欠点(それが正しい言葉の選択かどうかはわかりません)。拡張可能かどうかはわかりません\foreach
。- いくつかのメソッドは、明示的に渡されるか、マクロを介して暗黙的に渡されるかに関係なく、リストをかなりうまく処理します。たとえば、
pgffor
は、\foreach
マクロを介して渡されたリストをどのように処理するかを認識しています。 では、まずそのマクロを展開する必要がありetoolbox
ます\forcsvlist
。これが、 の最初の図が\forcslist
非常に複雑な理由です。
私がここで興味を持っているのは次の点です。
- この投稿の冒頭で箇条書きしたように、ここで提示されたさまざまなアプローチの長所と短所に対処する回答ですが、他の重要な問題を認識していない可能性があるため、必ずしもそれらの提案に限定されるわけではありません。たとえば、どれが拡張可能かはよくわかりません。
- 既知の弱点と強みとともに、アイテムのリストを反復処理するための他の方法を紹介する応答。
- 拡張可能なコンテキストでそのようなループを使用したい現実的な例を説明できる応答
- グループ内から収集した情報を後で使用するために保存する方法を示す応答。
答え1
私は別の定義を提案します\current@item
\def\current@item#1{%
\stepcounter{item@count}
\item $|$#1$|$\ $|$\texttt{\detokenize{#1}}$|$%
}
そのため、出力には実際に引数として渡されたものも表示されます。また、 の複雑な管理を\my@item@count
単純なカウンターに変更しました。 についてはコメントしません。\@tfor
は、カンマ区切りリスト用に設計されていない別のツールです。
etoolbox
:\forcsvlist
は末尾のスペースを削除しません。定義が複雑すぎるため、%% `etoolbox` \def\etoolbox@myloop#1{%% \forcsvlist\current@item{#1}}
十分です。項目は明示的に渡されます。
\@for
は、LaTeX カーネルで定義されている基本ツールです。先頭と末尾のスペースは削除されません。項目は\x
、 の後に使用される制御シーケンスとして渡されます\@for
。\foreach
末尾のスペースは削除されません。項目は\x
の後に使用される制御シーケンスとして渡されます\foreach
。ae
は基本的に と似ています\@for
が、拡張によって動作します。先頭と末尾のスペースは削除されません。項目は明示的に渡されます。expl
先頭と末尾のスペースを削除しますが、空の項目も削除します。項目は明示的に渡されます。
\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}
expl3
空の項目も考慮する別のループを追加します。
\ExplSyntaxOn
\NewDocumentCommand{\seq@myloop}{ m }
{
\seq_set_split:Nnn \l_tmpa_seq { , } { #1 }
\seq_map_inline:Nn \l_tmpa_seq { \current@item {##1} }
}
\ExplSyntaxOff
(もちろん、 を使用すること\l_tmpa_seq
は推奨されません。新しい変数を割り当てる方がよいでしょう)。
比較してみると、疑問の余地はありません。 が優れている唯一の点\foreach
は、 などの「不完全なリスト」の処理です1,2,...,20
。
答え2
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}