如何使用 foreach 语句从外部 csv 文件读取列?例如,如果 csv 文件的内容如下:
{0,0,0},black,
{1,1,0},yellow,
{1,0,1},pink
我想像下面的代码一样使用它。
\documentclass{standalone}
\usepackage{tikz}
\begin{document}
\foreach \code/\col in {%
{0,0,0}/black,
{1,1,0}/yellow,
{1,0,1}/pink
}{
\definecolor{tempcolor}{rgb}{\code}
\textcolor{tempcolor}{\col};
}
\end{document}
答案1
只要确保 .csv 文件的每一行都完全符合模式
{⟨rgb-specification⟩},⟨name of color⟩,
并且和 之间的逗号处没有空格,您可以:{⟨rgb-specification⟩}
⟨name of color⟩
- 使用 catchfile 包将 .csv 文件的内容放入临时宏中。
- 然后可以将一些替换例程(例如 xstring 包)应用于形成该临时宏的扩展/替换文本的标记。
- 之后,您可以将临时宏的扩展“馈送”给
\foreach
。
\documentclass{standalone}
\usepackage{tikz}
\usepackage{xstring}
\usepackage{catchfile}
\newcommand\PassFirstToSecond[2]{#2{#1}}
% !!! This will produce a text-file colorlist.csv for you.!!!
% !!! Make sure it won't override another already existing!!!
% !!! file of same name !!!
\begin{filecontents*}{colorlist.csv}
{0,0,0},black,
{1,1,0},yellow,
{1,0,1},pink
\end{filecontents*}
\begin{document}
\CatchFileDef{\tempa}{colorlist.csv}{}%
% Due to LaTeX's reading-apparatus which has that nice `\endlinechar`-thingie,
% reading and tokenizing colorlist.csv yields that each end of a line of
% colorlist.csv will result in the insertion of an explicit space token into
% the token stream.
% Thus the comma-character-tokens that stem from the commas at the ends of lines
% will be trailed by explicit space tokens while the comma-character-tokens that
% stem from commas not at the ends of lines don't have these trailing space tokens.
% The ending of the last line of colorlist.csv does also yield the insertion
% of an explicit space token.
% Anything nested inside curly braces is protected from being replaced by
% \StrSubstitute.
% Let's replace the commas at line endings by //:
\expandafter\StrSubstitute\expandafter{\tempa}{, }{//}[\tempa]%
%\show\tempa
% Let's replace the commas not at line endings by /:
\expandafter\StrSubstitute\expandafter{\tempa}{,}{/}[\tempa]%
%\show\tempa
% Let's replace the line endings (they are now denoted by //) by commas:
\expandafter\StrSubstitute\expandafter{\tempa}{//}{,}[\tempa]%
%\show\tempa
% Let's remove all remaining space-tokens - this does remove
% the space that came into being due to the end of the last
% line of colorlist.csv
\expandafter\StrSubstitute\expandafter{\tempa}{ }{}[\tempa]%
%\show\tempa
\expandafter\PassFirstToSecond\expandafter{\tempa}{\foreach\code/\col in}{%
\definecolor{tempcolor}{rgb}{\code}%
\textcolor{tempcolor}{\col};
}%
\end{document}
答案2
这假设 CSV 文件中的行具有相同数量的非空项目(允许尾随逗号)。
我们一次读取一行并将其传递进行处理;行以逗号分隔(忽略空行),这样获得的项目被括起来并作为参数传递给第二个参数中指定的宏\readcsv
。这样的宏应该具有与 CSV 文件中的列完全相同的参数数量。
我提供两个例子。
\begin{filecontents*}{\jobname.csv}
{0,0,0},black,
{0,1,1},cyan,
{1,0,1},pink
\end{filecontents*}
\begin{filecontents*}{\jobname2.csv}
{0,0,0},black,nero
{0,1,1},cyan,ciano
{1,0,1},pink,rosa
\end{filecontents*}
\documentclass{article}
\usepackage{xcolor}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\readcsv}{mm}
{% #1 = filename, #2 = macro to apply to each row
\tonytan_readcsv:nn { #1 } { #2 }
}
\ior_new:N \g_tonytan_readcsv_stream
\seq_new:N \l__tonytan_readcsv_temp_seq
\tl_new:N \l__tonytan_readcsv_temp_tl
\cs_new_protected:Nn \tonytan_readcsv:nn
{
\ior_open:Nn \g_tonytan_readcsv_stream { #1 }
\ior_map_inline:Nn \g_tonytan_readcsv_stream
{
\tonytan_readcsv_generic:Nn #2 { ##1 }
}
\ior_close:N \g_tonytan_readcsv_stream
}
\cs_new_protected:Nn \tonytan_readcsv_generic:Nn
{
\seq_set_from_clist:Nn \l__tonytan_readcsv_temp_seq { #2 }
\tl_set:Nx \l__tonytan_readcsv_temp_tl
{
\seq_map_function:NN \l__tonytan_readcsv_temp_seq \__tonytan_readcsv_brace:n
}
\exp_last_unbraced:NV #1 \l__tonytan_readcsv_temp_tl
}
\cs_new:Nn \__tonytan_readcsv_brace:n { {#1} }
\ExplSyntaxOff
\newcommand{\showcolor}[2]{\textcolor[rgb]{#1}{#2}\par}
\newcommand{\showcolorx}[3]{\textcolor[rgb]{#1}{#2} (#3)\par}
\begin{document}
\readcsv{\jobname.csv}{\showcolor}
\readcsv{\jobname2.csv}{\showcolorx}
\end{document}
答案3
在这里,我使用readarray
将文件放入然后\def
(listofitems
包含在内readarray
)对其进行解析并循环。
\documentclass{standalone}
\usepackage{tikz,readarray,filecontents}
\begin{filecontents*}{mydata.csv}
{0,0,0},black,
{1,1,0},yellow,
{1,0,1},pink
\end{filecontents*}
\begin{document}
\readarraysepchar{\\}%
\readdef{mydata.csv}\mydata%
\ignoreemptyitems%
\setsepchar{\\/,}%
\readlist\mylist{\mydata}%
\foreachitem\x\in\mylist{%
\def\tmp{\definecolor{tempcolor}{rgb}}%
\expandafter\expandafter\expandafter\tmp\mylist[\xcnt,1]%
\textcolor{tempcolor}{\mylist[\xcnt,2]};%
}
\end{document}
答案4
玩了一段时间后,我认为 datatool 更适合我的需求。谢谢大家的帮助!
\documentclass{standalone}
\usepackage{tikz,datatool,filecontents}
\begin{filecontents*}{mydata.csv}
code,text,
{0,0,0},black,
{1,1,0},yellow,
{1,0,1},pink
\end{filecontents*}
\DTLsetseparator{,}
\DTLloaddb{myfile}{mydata.csv}
\begin{document}
\DTLforeach*
{myfile}
{\code=code,\text=text}% assignment
{% Stuff to do at each iteration:
\expandafter\expandafter\definecolor{tempcolor}{rgb}{\code}
\textcolor{tempcolor}{\text}
}
\end{document}