我正在尝试从配置文件中读取可变长度的列表,以便对 if 执行某些操作。
列表存储在文件中如下
list_1:x1, x2, x3
list_2:y1, y2
如果我读了数据工具包,我可以打印它们
\usepackage{datatool}
\DTLsetseparator{:}
\DTLloaddb[noheader, keys={key,value}]{config}{path_to_config_file}
\newcommand{\firstlist}{\DTLfetch{config}{key}{list_1}{value}}
\newcommand{\secondlist}{\DTLfetch{config}{key}{list_2}{value}}
...
\firstlist
\secondlist
这将打印以下输出
x1、x2、x3
y1,y2
然后我尝试将它们传递给\foreach
来自前列腺素包裹
\usepackage{pgffor}
\foreach \x in { \firstlist}{%
\foreach \y in {\secondlist}{%
Value: \x \y
}
}
我得到以下输出:
值:x1、x2、x3 y1、y2
我究竟做错了什么?
提前致谢!
答案1
您可以使用\DTLassignfirstmatch
,它可以定义扩展到值的宏。还要注意它应该是\foreach \x \in \firstlist
(没有括号)。
\begin{filecontents*}{\jobname.dat}
list_1:x1, x2, x3
list_2:y1, y2
\end{filecontents*}
\documentclass{article}
\usepackage{pgffor}
\usepackage{datatool}
\DTLsetseparator{:}
\DTLloaddb[noheader, keys={key,value}]{config}{\jobname.dat}
\DTLassignfirstmatch{config}{key}{list_1}{\firstlist=value}
\DTLassignfirstmatch{config}{key}{list_2}{\secondlist=value}
\begin{document}
\foreach \x in \firstlist {%
\foreach \y in \secondlist {%
Value: \x \y \par
}
}
\end{document}
通常警告:我使用它filecontents*
只是为了让示例自成一体。
你的\firstlist
宏本质上是一组(复杂的)指令打印 x1, x2, x3
并且不能在的上下文中使用\foreach
,因为它需要直接扩展为列表的宏。
答案2
这用于readarray
输入配置文件并listofitems
对其进行解析。已编辑以在配置文件中提供标题行,并且不预先假定列表名称中的命名约定。为此,我将配置文件读取为“原始”记录数组,丢弃第一行并编写“熟”配置,其中每个记录现在都以单词开头LISTNAME
。这设置为使用listofitems
执行 3 层解析以\cookedconfig
分离LISTNAME
记录,然后:
将列表名称与列表数据分离,最后,
分离列表数据的组件。
从那里开始,循环使用两者\foreach
并\foreachitem
自行编写。
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{readarray,filecontents,pgffor,lmodern}
\begin{filecontents*}{config}
This is a header row
list A:x1, x2, x3
lstB :y1, y2
\end{filecontents*}
\begin{document}
\readrecordarray{config}\rawconfig
\def\cookedconfig{}
\makeatletter
\foreach\row in{2,...,\numexpr\rawconfigROWS-1}{%
\g@addto@macro\cookedconfig{LISTNAME}%
\arraytomacro\rawconfig[\row]\thisrow%
\expandafter\g@addto@macro\expandafter\cookedconfig\expandafter{\thisrow}%
}
\makeatother
\ignoreemptyitems
\setsepchar{LISTNAME/:/,}
\readlist*\myconfig{\cookedconfig}
The list names are:\par
\foreach\row in {1,...,\listlen\myconfig[]}{%
\texttt{\myconfig[\row,1]}, consisting of
\foreachitem\x\in\myconfig[\row,2]{%
\ifnum\xcnt=1\else, \fi\texttt{\x}}
\par
}
The desired loop of the OP is
\foreachitem\x\in\myconfig[1,2]{%
\foreachitem\y\in\myconfig[2,2]{%
Value \texttt{\x{} \y}\par
}}%
\end{document}
\readdef
甚至可以使用在每个记录之间插入字符的“技巧” LISTNAME
,从而节省一点代码:
\documentclass{article}
\usepackage{readarray,filecontents,pgffor,lmodern}
\begin{filecontents*}{config}
This is a header row
list A:x1, x2, x3
lstB :y1, y2
\end{filecontents*}
\newcommand\cookconfig[1]{\expandafter\cookconfigaux#1\endcookconfig}
\def\cookconfigaux#1LISTNAME#2\endcookconfig{\gdef\cookedconfig{LISTNAME#2}}
\begin{document}
\readarraysepchar{LISTNAME}
\readdef{config}\rawconfig
\cookconfig{\rawconfig}
\setsepchar{LISTNAME/:/,}
\ignoreemptyitems
\readlist*\myconfig{\cookedconfig}
The list names are:\par
\foreach\row in {1,...,\listlen\myconfig[]}{%
\texttt{\myconfig[\row,1]}, consisting of
\foreachitem\x\in\myconfig[\row,2]{%
\ifnum\xcnt=1\else, \fi\texttt{\x}}
\par
}
The desired loop of the OP is
\foreachitem\x\in\myconfig[1,2]{%
\foreachitem\y\in\myconfig[2,2]{%
Value \texttt{\x{} \y}\par
}}%
\end{document}