为什么从 foreach 循环调用时 \test 命令不拆分参数?
\NewDocumentCommand{\test}{ >{\SplitArgument{3}{|}} m }{\printtest#1}
\NewDocumentCommand{\printtest}{mmmm}{
(#1,#2)\quad s_{\IfValueT{#3}{#3}}\IfValueT{#4}{#4}}
\newcommand{\looptest}[1]{
\foreach \n in {#1}{
$\test{\n}$\\
};
$\test{1|1}$\\ % this works
$\test{2|2|1}$\\ % this works
$\test{3|3|2|'}$\\ % this works
$\test{4|4|3|''}$\\ % this works
\looptest{1|2|1, 3|7|2, 6|7|3, 6|5, 9|5|3|''} % this does not
答案1
参数没有及时展开。每个 foreach 旋转参数仍然在括号对内。另外,不要在 foreach 参数内使用空格。这可能会导致模式不匹配。
\documentclass{article}
\usepackage{pgffor,xparse}
\NewDocumentCommand{\test}{ >{\SplitArgument{3}{|}} m }{\printtest#1}
\NewDocumentCommand{\printtest}{mmmm}{(#1,#2)\quad s_{\IfValueT{#3}{#3}}\IfValueT{#4}{#4}}
\newcommand{\looptest}[1]{\foreach\n in{#1}{$\expandafter\test\expandafter{\n}$\\}}
\begin{document}\noindent
$\test{1|1}$\\ % this works
$\test{2|2|1}$\\ % this works
$\test{3|3|2|'}$\\ % this works
$\test{4|4|3|''}$\\ % this works
\looptest{1|2|1,3|7|2,6|7|3,6|5,9|5|3|''} % this does not
\end{document}
答案2
这使用一种listofitems
方法将输入解析为\looptest
。介绍性\setsepchar{,}
将解析字符设置为,
。宏\readlist*\looplist{#1}
将列表解析为\looplist[<index>]
数组(同时忽略分隔符周围的空格,
),然后使用\foreachitem
循环按顺序访问该数组。但是,循环参数\n
在被 消化之前必须展开一次\test
。
\documentclass{article}
\usepackage{pgffor,xparse,listofitems}
\NewDocumentCommand{\test}{ >{\SplitArgument{3}{|}} m }{\printtest#1}
\NewDocumentCommand{\printtest}{mmmm}{
(#1,#2)\quad s_{\IfValueT{#3}{#3}}\IfValueT{#4}{#4}}
\newcommand{\looptest}[1]{%
\setsepchar{,}%
\readlist*\looplist{#1}%
\foreachitem \n \in \looplist{%
$\expandafter\test\expandafter{\n}$\\
}
}
\begin{document}\noindent
$\test{1|1}$\\ % this works
$\test{2|2|1}$\\ % this works
$\test{3|3|2|'}$\\ % this works
$\test{4|4|3|''}$\\ % this works
\noindent\looptest{1|2|1, 3|7|2, 6|7|3, 6|5, 9|5|3|''} % this does not
\end{document}
这里有一种方法可以完全消除pgffor
和xparse
,完全在内完成listofitems
。请注意,不仅可以在列表逗号周围引入杂散空格,
,还可以在|
分隔符周围引入杂散空格,而不会产生任何不良影响。
\documentclass{article}
\usepackage{listofitems}
\makeatletter
\newcommand\test[1]{%
\setsepchar{{|}}%
\readlist*\testlist{#1}%
\def\temp{\printtest}%
\foreachitem\testitem\in\testlist{%
\expandafter\g@addto@macro\expandafter\temp\expandafter{\expandafter{\testitem}}%
}%
\temp\relax\relax\relax%
}
\makeatother
\newcommand\printtest[4]{(#1,#2)\quad s_{#3}#4}
\newcommand{\looptest}[1]{%
\setsepchar{,}%
\readlist*\looplist{#1}%
\foreachitem \n \in \looplist{%
$\expandafter\test\expandafter{\n}$\\
}%
}
\begin{document}\noindent
$\test{1|1}$\\ % this works
$\test{2|2|1}$\\ % this works
$\test{3|3|2|'}$\\ % this works
$\test{4|4|3|''}$\\ % this works
\noindent\looptest{1|2|1, 3|7|2, 6|7|3, 6|5, 9|5|3|''} % this does not
\end{document}