我想使用 循环遍历多个句子foreach loop
。现在句子可能包含逗号,逗号用作foreach
项目分隔符。因此,我想将项目分隔符更改为句子中未出现的内容,例如|
因此,
\foreach \x in {sentenceA,sentenceB,sentenceC}
我想使用
\foreach \x in {sentenceA|sentenceB|sentenceC}
这可能吗?
答案1
这是一个expl3
实现:
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{xparse,pgffor}
\ExplSyntaxOn
\NewDocumentCommand{\Foreach}{ m O{,} m}
{
\__foreach_main:nn { #1 } { #2 } { #3 }
}
\seq_new:N \l__foreach_arg_seq
\clist_new:N \l__foreach_braced_clist
\cs_new_protected:Npn \__foreach_main:nn #1 #2 #3
{
\seq_set_split:Nnn \l__foreach_arg_seq { #2 } { #3 }
\clist_clear:N \l__foreach_braced_clist
\seq_map_inline:Nn \l__foreach_arg_seq
{
\clist_put_right:Nn \l__foreach_braced_clist { { ##1 } }
}
\foreach #1 in~\l__foreach_braced_clist
}
\ExplSyntaxOff
\begin{document}
\Foreach{\x}[|]{sentenceA|se,nt,en,ce,B| sentenceC }{[\x]}
\Foreach{\x}{sentenceA|se,nt,en,ce,B| sentenceC }{[\x]}
\end{document}
语法与 略有不同\foreach \x in {...}
,但这不应该是一个大问题。默认分隔符是逗号,可以在变量后的可选参数中指定其他分隔符。
答案2
逗号在 中是硬编码的pgffor
。\foreach
您可以转换之前的列表并将其存储在宏中。以下示例将条目放在花括号中以保护逗号。然后还保留了首空格和尾空格。在示例中,仅删除了首空格。
\documentclass{article}
\usepackage{pgffor}
\makeatletter
\newcommand{\tocommalist}[3]{%
\begingroup
\toks@{}
\let\@tmp\relax
\long\def\@tocommalist##1#2##2\@nil{%
\ifx\@tmp\relax
% \toks@{{##1}}% without initial trimming
\toks@\expandafter{\expandafter{\romannumeral-`\x##1}}%
\else
% \toks@\expandafter{\the\toks@,{##1}}% without initial trimming
\toks@\expandafter{%
\the\expandafter\toks@\expandafter,%
\expandafter{\romannumeral-`\x##1}%
}%
\fi
\def\@tmp{##2}%
\ifx\@tmp\@empty
\expandafter\@gobbletwo
\fi
\@tocommalist##2\@nil
}%
\@tocommalist#3#2\@nil
\expandafter\endgroup
\expandafter\def\expandafter#1\expandafter{\the\toks@}%
}
\makeatother
\tocommalist\mylist{|}{sentenceA|se,nt,en,ce,B| sentenceC }
\foreach \x in \mylist {%
\typeout{[\meaning\x]}%
}
\begin{document}
\foreach \x in \mylist {%
[\x]\par
}
\end{document}
另一个使用包的示例etoolbox
。它也仅修剪条目的开头并删除空条目:
\documentclass{article}
\usepackage{pgffor}
\usepackage{etoolbox}
\usepackage{etexcmds}
\DeclareListParser*{\forvertlist}{|}
\makeatletter
\newcommand{\vertocomma}[2]{%
\let#1\@empty
\forvertlist{\@verttocomma{#1}}{#2}%
}
\newcommand{\@verttocomma}[2]{%
\edef#1{%
\ifx#1\@empty
\else
\etex@unexpanded\expandafter{#1},%
\fi
{\etex@unexpanded{#2}}%
}%
}
\makeatother
\vertocomma\mylist{sentenceA|| |se,nt,en,ce,B| sentenceC |}
\foreach \x in \mylist {%
\typeout{[\meaning\x]}%
}
\begin{document}
\foreach \x in \mylist {%
[\x]\par
}
\end{document}
答案3
当不需要自动列表完成时,期权包\indrisloop
可以处理任何列表分隔符。\newforeach
宏自然可以接受任何类型的列表分隔符,并且可以完成列表完成,但它尚未在 CTAN 上实现。这是一个\indrisloop
解决方案。即使列表分隔符处于活动状态,这也应该有效。正如您将在示例结果中注意到的那样,列表元素之间的虚假空格被删除了。
\documentclass{article}
\usepackage{catoptions}
\begin{document}
\def\bombadil#1{%
\typeout{Doing item: #1}%
\edef\transformedlist{%
\ifdefFT\transformedlist{}{\expandcsonce\transformedlist}%
\unexpanded{\\{#1}}%
}%
}
% \indrisloop[<separator>]{<list>}{<callback>}
\indrisloop[|]{%
David Carlisle, item 1 |
Heiko Oberdiek, item 2 |
David Salomon, item 3 |
Frank Mittelbach, item 4 |
Donald Arseneau; item 5
}\bombadil
\show\transformedlist
\end{document}
{\show}
> \transformedlist=macro:
\\{David Carlisle, item 1}\\{Heiko Oberdiek, item 2}\\{David Salomon, item 3}
\\{Frank Mittelbach, item 4}\\{Donald Arseneau; item 5}.
l.21 \show\transformedlist
DE Knuth 喜欢用作\\
列表分隔符。
您可以使用以下命令将任意列表转换为逗号分隔的列表\makeintocommalist
。
% \makeintocommalist{<original.parser>}{<orig.list.cmd>}{<transformed.list.cmd>}
\def\makeintocommalist#1#2#3{%
\def#3{}%
\def\bombadil##1{%
\edef#3{%
\expandcsonce#3{\unexpanded{##1}}%
\iflastindris\else,\fi
}%
}%
\indrisloop*[#1]{#2}\bombadil
}
例子:
\def\alist{%
David Carlisle, item 1 |
Heiko Oberdiek, item 2 |
David Salomon, item 3 |
Frank Mittelbach, item 4 |
Donald Arseneau; item 5 |
Enrico Gregorio/another great |
Ulrich Diez, yes! |
Joseph Wright, also/+
}
\makeintocommalist{|}\alist\blist
\show\blist
> \blist=macro:->
{David Carlisle, item 1},{Heiko Oberdiek, item 2},{David Salomon, item 3},
{Frank Mittelbach, item 4},{Donald Arseneau; item 5},{Enrico Gregorio/another great},
{Ulrich Diez, yes!},{Joseph Wright, also/+}.
l.53 \show\blist
编辑
现在我记得期权软件包中有一个\cptforeach
命令可以完全满足您的要求。但是它不能自动完成列表。请看下面的操作。它可以处理任意(甚至奇怪的)列表项分隔符。
% \cptforeach[<optional.sep>] <holders> \in <list> \do {<callback>}
% Note the list separators in these loops:
\tikz[shading=ball]
\cptforeach[:] \x+\cola \in 0+red : 1+green : 2+blue : 3+yellow \do {%
\cptforeach[|] \y;\colb \in {0;red | 1;green | 2;blue | 3;yellow} \do {%
\shade[ball color=\cola!50!\colb] (\x,\y) circle (0.4cm);
}%
};
以上相当于
\tikz[shading=ball]
\cptforeach \x/\cola \in 0/red, 1/green, 2/blue, 3/yellow \do {%
\cptforeach \y/\colb \in {0/red, 1/green, 2/blue, 3/yellow} \do {%
\shade[ball color=\cola!50!\colb] (\x,\y) circle (0.4cm);
}%
};
答案4
使用括号 { aaa,nnn!} 分隔项目
\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\foreach \nn in{{0,1},{1,0},{0,-1},{-1,0}}{
\draw (0,0) -- (\nn);
}
\end{tikzpicture}
\end{document}