\documentclass[a4paper]{article}
\usepackage{tikz,etoolbox}
\usepackage{geometry}
\geometry{showframe}
\geometry{left=1cm,right=1cm,top=1cm,bottom=1cm}
\parindent0pt
\begin{document}
Method 1: %by \docsvlist from etoolbox
% This does not work. How make it work?
\def\lst{}
\appto\lst{1in,1pt,}
\appto\lst{2in,2pt,}
\appto\lst{3in,3pt,}
% length with unit in is for rule width, length with unit pt is for rule height
\renewcommand{\do}[2]{\rule{#1}{#2}\\}
\docsvlist\lst
%----------------------------------------
\def\aaa{1,2,3,}
\foreach \x in \aaa{\x}
% The above \foreach works well thought there is an extra comma in the list of \aaa.
Method 2:\\ % by \foreach from tikz
\def\lst{}
\appto\lst{1in/1pt,}
\appto\lst{2in/2pt,}
\appto\lst{3in/3pt,}
\lst
% The following \foreach gives error. I think this is due to the last comma in \lst.
% So, how to solve this problem?
\foreach \x/\y in \lst{\rule{\x}{\y}}
\end{document}
答案1
您可以使用稍微不同的输入语法etoolbox
:\listadd
\documentclass{article}
\usepackage{etoolbox}
\begin{document}
\newcommand\lst{}
\listadd\lst{{1in}{1pt}}
\listadd\lst{{2in}{2pt}}
\listadd\lst{{3in}{3pt}}
\renewcommand\do[1]{\rule#1\par}
\dolistloop{\lst}
\newcommand\handler[2]{\hspace{#1} \rule{1in}{#2}\par}
\renewcommand\do[1]{\handler#1\par}
\dolistloop{\lst}
\end{document}
答案2
问题确实出在最后一个列表项末尾的额外逗号。您还可以在简单循环中看到这一点,当您在每个列表项后打印一个字符时,它将为最后一个空列表项打印一个额外的字符。这将失败,\foreach
因为无法正确解析最后一个空项。
解决方案很简单:删除最后一个逗号,或者一开始就不添加它。在列表构建期间确定您处于最后一个项目,在这种情况下只添加不带逗号的项目会很有用。如果这很困难,那么作为一种解决方法,您可以使用包\StrGobbleRight
中的逗号删除逗号xstring
。
\documentclass[a4paper]{article}
\usepackage{tikz,etoolbox}
\usepackage{geometry}
\usepackage{xstring}
\geometry{showframe}
\geometry{left=1cm,right=1cm,top=1cm,bottom=1cm}
\parindent0pt
\begin{document}
\def\aaa{1,2,3,}
\foreach \x in \aaa{\x a}
% The above \foreach works well thought there is an extra comma in the list of \aaa.
Method 2:\\ % by \foreach from tikz
\def\lst{}
\appto\lst{1in/1pt,}
\appto\lst{2in/2pt,}
\appto\lst{3in/3pt,}
% remove 1 character from the right and store the result back in `\lst`
\StrGobbleRight{\lst}{1}[\lst]
\lst\\
% The following \foreach gives error. I think this is due to the last comma in \lst.
% So, how to solve this problem?
\foreach \x/\y in \lst{\rule{\x}{\y}\\}
\end{document}
结果:
答案3
您不想使用“裸的” \appto
,而是构建自己的列表构造函数,因此您不需要担心逗号。
\newcommand{\addtolist}[2]{%
\ifdefvoid{#1}{\appto{#1}{#2}}{\appto{#1}{,#2}}%
}
例子:
\documentclass[a4paper]{article}
\usepackage{tikz,etoolbox}
\newcommand{\addtolist}[2]{%
\ifdefvoid{#1}{\appto{#1}{#2}}{\appto{#1}{,#2}}%
}
\begin{document}
\addtolist\lst{1in/1pt}
\addtolist\lst{2in/2pt}
\addtolist\lst{3in/3pt}
\foreach \x/\y in \lst{\rule{\x}{\y}\par}
\end{document}
您可能需要一个独立于tikz
和的实现etoolbox
。
这\lforeach
命令将作为第一个参数姓名列表(无反斜杠),第二个强制参数是应用于每个列表元素的代码。中间有一个可选参数设置图案列表元素必须遵守的规则。如果缺少此参数,则#1
使用通用规则。
请注意,这不是按组执行的。可以允许嵌套,但对于概念验证来说会变得复杂。
\documentclass[a4paper]{article}
\ExplSyntaxOn
\NewDocumentCommand{\lforeach}{mo+m}
{
\IfNoValueTF{#2}
{
\cs_set:Npn \__lyl_lforeach_do:w ##1 \q_stop { #3 }
}
{
\cs_set:Npn \__lyl_lforeach_do:w #2 \q_stop { #3 }
}
\__lyl_lforeach_main:n { #1 }
}
\NewDocumentCommand{\newlist}{m}
{
\clist_clear_new:c { l__lyl_lforeach_#1_clist }
}
\NewDocumentCommand{\addtolist}{mm}
{
\clist_map_inline:nn { #2 }
{
\clist_put_right:cn { l__lyl_lforeach_#1_clist } { ##1 }
}
}
\cs_new_protected:Nn \__lyl_lforeach_main:n
{
\clist_map_function:cN { l__lyl_lforeach_#1_clist } \__lyl_lforeach_do:n
}
\cs_new:Nn \__lyl_lforeach_do:n { \__lyl_lforeach_do:w #1 \q_stop }
\cs_new:Npn \__lyl_lforeach_do:w {}
\ExplSyntaxOff
\begin{document}
\newlist{lst}
\addtolist{lst}{1in/1pt}
\addtolist{lst}{2in/2pt, 3in/3pt}
\newlist{lsta}
\addtolist{lsta}{1in}
\addtolist{lsta}{2in, 3in}
\newlist{lstb}
\addtolist{lstb}{(1in;1pt)}
\addtolist{lstb}{(2in;2pt), (3in;3pt)}
\lforeach{lst}[#1/#2]{\rule{#1}{#2}\par}
\lforeach{lsta}{\rule{#1}{0.4pt}\par}
\lforeach{lstb}[(#1;#2)]{\rule{#1}{#2}\par}
\end{document}
您还可以为常见结构创建自己的命令;例如,当列表项的形式为 时<a>/<b>
,您可以定义
\newcommand{\lforeachslash}[2]{\lforeach{#1}[##1/##2]{#2}}
和
\lforeachslash{lst}{\rule{#1}{#2}\par}
会产生与 相同的结果\lforeach{lst}[#1/#2]{\rule{#1}{#2}\par}
。
答案4
这是另一种解决方案functional
包裹:
\documentclass{article}
\usepackage{functional}
\begin{document}
\clistNew \lMyClist
\clistPutRight \lMyClist {{1in}{1pt}}
\clistPutRight \lMyClist {{2in}{2pt}}
\clistPutRight \lMyClist {{3in}{3pt}}
\NewDocumentCommand \DoMyClist {m} {%
\clistVarMapInline #1 {%
\rule ##1\par
}%
}
\DoMyClist \lMyClist
\end{document}