use foreach to read columns from a csv file?
How can I read columns from a external csv file using a foreach statement? e.g. if the content of the csv file is as follows:
{0,0,0},black,
{1,1,0},yellow,
{1,0,1},pink
And I would like to use it as in the following code.
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}
xetex datatool csv
add a comment |
How can I read columns from a external csv file using a foreach statement? e.g. if the content of the csv file is as follows:
{0,0,0},black,
{1,1,0},yellow,
{1,0,1},pink
And I would like to use it as in the following code.
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}
xetex datatool csv
add a comment |
How can I read columns from a external csv file using a foreach statement? e.g. if the content of the csv file is as follows:
{0,0,0},black,
{1,1,0},yellow,
{1,0,1},pink
And I would like to use it as in the following code.
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}
xetex datatool csv
How can I read columns from a external csv file using a foreach statement? e.g. if the content of the csv file is as follows:
{0,0,0},black,
{1,1,0},yellow,
{1,0,1},pink
And I would like to use it as in the following code.
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}
xetex datatool csv
xetex datatool csv
edited Jan 28 at 6:58
Hafid Boukhoulda
3,0921520
3,0921520
asked Jan 28 at 6:49
Tony TanTony Tan
1237
1237
add a comment |
add a comment |
4 Answers
4
active
oldest
votes
As long as it is ensured that each line of your .csv-file is exactly of pattern
{⟨rgb-specification⟩},⟨name of color⟩,
and that there are no spaces at the commas that separate the {⟨rgb-specification⟩}
from the ⟨name of color⟩
, you can:
- use the catchfile-package for getting the content of the .csv-file into a temporary macro.
- Then can apply some replacement-routine, e.g., of the xstring package, to the tokens that form the expansion/replacement-text of that temporary macro.
- After that you can "feed" the expansion of the temporary macro to
foreach
.
documentclass{standalone}
usepackage{tikz}
usepackage{xstring}
usepackage{catchfile}
newcommandPassFirstToSecond[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 //:
expandafterStrSubstituteexpandafter{tempa}{, }{//}[tempa]%
%showtempa
% Let's replace the commas not at line endings by /:
expandafterStrSubstituteexpandafter{tempa}{,}{/}[tempa]%
%showtempa
% Let's replace the line endings (they are now denoted by //) by commas:
expandafterStrSubstituteexpandafter{tempa}{//}{,}[tempa]%
%showtempa
% 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
expandafterStrSubstituteexpandafter{tempa}{ }{}[tempa]%
%showtempa
expandafterPassFirstToSecondexpandafter{tempa}{foreachcode/col in}{%
definecolor{tempcolor}{rgb}{code}%
textcolor{tempcolor}{col};
}%
end{document}
add a comment |
This assumes that the rows in the CSV file have the same number of nonempty items (trailing commas allowed).
We read one row at a time and pass it for processing; the row is split at commas (ignoring empty lines), the items so obtained are braced and passed as arguments to the macro specified in the second argument to readcsv
. Such a macro should have the exact number of arguments as the columns in the CSV file.
I provide two examples.
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}
add a comment |
Here, I use readarray
to get the file into a def
and then listofitems
(included in readarray
) to parse it and loop over it.
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{\/,}%
readlistmylist{mydata}%
foreachitemxinmylist{%
deftmp{definecolor{tempcolor}{rgb}}%
expandafterexpandafterexpandaftertmpmylist[xcnt,1]%
textcolor{tempcolor}{mylist[xcnt,2]};%
}
end{document}
@ Steven B. Segletes I accepted Steven's code as answer due to its simplicity and its resistance to irregularity of CSV list (e.g. empty spaces or lines). Thank you all!
– Tony Tan
Jan 28 at 18:50
1
@TonyTan If you want surrounding spaces in the data to be ignored, you can change thereadlist
toreadlist*
. Then, leading/trailing blanks are excised from the parsed data.
– Steven B. Segletes
Jan 28 at 19:35
Is there easy way to assignmylist[xcnt,2]
tocol
andmylist[xcnt,1]
tocode
in foreach statement as I did in my original post? or even better, can I put the header in the CSV file? I can not find a clue from the readarray manual.
– Tony Tan
Jan 28 at 20:39
@TonyTan Let me think about your request, but perhaps look at thelistofitems
manual as well: ctan.org/pkg/listofitems
– Steven B. Segletes
Jan 28 at 20:55
1
@TonyTan If your own answer is not a duplicate of others, post away. Inlistofitems
, the way to skip the header isforeachitemxin<listname>{ifnumxcnt=1else...<your loop code here>...fi}
– Steven B. Segletes
Jan 29 at 2:38
|
show 2 more comments
After playing with it for a while, I think that datatool is a better tool for what I need. Thanks everyone for helping!
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:
expandafterexpandafterdefinecolor{tempcolor}{rgb}{code}
textcolor{tempcolor}{text}
}
end{document}
add a comment |
Your Answer
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "85"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f472182%2fuse-foreach-to-read-columns-from-a-csv-file%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
As long as it is ensured that each line of your .csv-file is exactly of pattern
{⟨rgb-specification⟩},⟨name of color⟩,
and that there are no spaces at the commas that separate the {⟨rgb-specification⟩}
from the ⟨name of color⟩
, you can:
- use the catchfile-package for getting the content of the .csv-file into a temporary macro.
- Then can apply some replacement-routine, e.g., of the xstring package, to the tokens that form the expansion/replacement-text of that temporary macro.
- After that you can "feed" the expansion of the temporary macro to
foreach
.
documentclass{standalone}
usepackage{tikz}
usepackage{xstring}
usepackage{catchfile}
newcommandPassFirstToSecond[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 //:
expandafterStrSubstituteexpandafter{tempa}{, }{//}[tempa]%
%showtempa
% Let's replace the commas not at line endings by /:
expandafterStrSubstituteexpandafter{tempa}{,}{/}[tempa]%
%showtempa
% Let's replace the line endings (they are now denoted by //) by commas:
expandafterStrSubstituteexpandafter{tempa}{//}{,}[tempa]%
%showtempa
% 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
expandafterStrSubstituteexpandafter{tempa}{ }{}[tempa]%
%showtempa
expandafterPassFirstToSecondexpandafter{tempa}{foreachcode/col in}{%
definecolor{tempcolor}{rgb}{code}%
textcolor{tempcolor}{col};
}%
end{document}
add a comment |
As long as it is ensured that each line of your .csv-file is exactly of pattern
{⟨rgb-specification⟩},⟨name of color⟩,
and that there are no spaces at the commas that separate the {⟨rgb-specification⟩}
from the ⟨name of color⟩
, you can:
- use the catchfile-package for getting the content of the .csv-file into a temporary macro.
- Then can apply some replacement-routine, e.g., of the xstring package, to the tokens that form the expansion/replacement-text of that temporary macro.
- After that you can "feed" the expansion of the temporary macro to
foreach
.
documentclass{standalone}
usepackage{tikz}
usepackage{xstring}
usepackage{catchfile}
newcommandPassFirstToSecond[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 //:
expandafterStrSubstituteexpandafter{tempa}{, }{//}[tempa]%
%showtempa
% Let's replace the commas not at line endings by /:
expandafterStrSubstituteexpandafter{tempa}{,}{/}[tempa]%
%showtempa
% Let's replace the line endings (they are now denoted by //) by commas:
expandafterStrSubstituteexpandafter{tempa}{//}{,}[tempa]%
%showtempa
% 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
expandafterStrSubstituteexpandafter{tempa}{ }{}[tempa]%
%showtempa
expandafterPassFirstToSecondexpandafter{tempa}{foreachcode/col in}{%
definecolor{tempcolor}{rgb}{code}%
textcolor{tempcolor}{col};
}%
end{document}
add a comment |
As long as it is ensured that each line of your .csv-file is exactly of pattern
{⟨rgb-specification⟩},⟨name of color⟩,
and that there are no spaces at the commas that separate the {⟨rgb-specification⟩}
from the ⟨name of color⟩
, you can:
- use the catchfile-package for getting the content of the .csv-file into a temporary macro.
- Then can apply some replacement-routine, e.g., of the xstring package, to the tokens that form the expansion/replacement-text of that temporary macro.
- After that you can "feed" the expansion of the temporary macro to
foreach
.
documentclass{standalone}
usepackage{tikz}
usepackage{xstring}
usepackage{catchfile}
newcommandPassFirstToSecond[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 //:
expandafterStrSubstituteexpandafter{tempa}{, }{//}[tempa]%
%showtempa
% Let's replace the commas not at line endings by /:
expandafterStrSubstituteexpandafter{tempa}{,}{/}[tempa]%
%showtempa
% Let's replace the line endings (they are now denoted by //) by commas:
expandafterStrSubstituteexpandafter{tempa}{//}{,}[tempa]%
%showtempa
% 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
expandafterStrSubstituteexpandafter{tempa}{ }{}[tempa]%
%showtempa
expandafterPassFirstToSecondexpandafter{tempa}{foreachcode/col in}{%
definecolor{tempcolor}{rgb}{code}%
textcolor{tempcolor}{col};
}%
end{document}
As long as it is ensured that each line of your .csv-file is exactly of pattern
{⟨rgb-specification⟩},⟨name of color⟩,
and that there are no spaces at the commas that separate the {⟨rgb-specification⟩}
from the ⟨name of color⟩
, you can:
- use the catchfile-package for getting the content of the .csv-file into a temporary macro.
- Then can apply some replacement-routine, e.g., of the xstring package, to the tokens that form the expansion/replacement-text of that temporary macro.
- After that you can "feed" the expansion of the temporary macro to
foreach
.
documentclass{standalone}
usepackage{tikz}
usepackage{xstring}
usepackage{catchfile}
newcommandPassFirstToSecond[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 //:
expandafterStrSubstituteexpandafter{tempa}{, }{//}[tempa]%
%showtempa
% Let's replace the commas not at line endings by /:
expandafterStrSubstituteexpandafter{tempa}{,}{/}[tempa]%
%showtempa
% Let's replace the line endings (they are now denoted by //) by commas:
expandafterStrSubstituteexpandafter{tempa}{//}{,}[tempa]%
%showtempa
% 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
expandafterStrSubstituteexpandafter{tempa}{ }{}[tempa]%
%showtempa
expandafterPassFirstToSecondexpandafter{tempa}{foreachcode/col in}{%
definecolor{tempcolor}{rgb}{code}%
textcolor{tempcolor}{col};
}%
end{document}
answered Jan 28 at 12:06
Ulrich DiezUlrich Diez
4,500616
4,500616
add a comment |
add a comment |
This assumes that the rows in the CSV file have the same number of nonempty items (trailing commas allowed).
We read one row at a time and pass it for processing; the row is split at commas (ignoring empty lines), the items so obtained are braced and passed as arguments to the macro specified in the second argument to readcsv
. Such a macro should have the exact number of arguments as the columns in the CSV file.
I provide two examples.
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}
add a comment |
This assumes that the rows in the CSV file have the same number of nonempty items (trailing commas allowed).
We read one row at a time and pass it for processing; the row is split at commas (ignoring empty lines), the items so obtained are braced and passed as arguments to the macro specified in the second argument to readcsv
. Such a macro should have the exact number of arguments as the columns in the CSV file.
I provide two examples.
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}
add a comment |
This assumes that the rows in the CSV file have the same number of nonempty items (trailing commas allowed).
We read one row at a time and pass it for processing; the row is split at commas (ignoring empty lines), the items so obtained are braced and passed as arguments to the macro specified in the second argument to readcsv
. Such a macro should have the exact number of arguments as the columns in the CSV file.
I provide two examples.
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}
This assumes that the rows in the CSV file have the same number of nonempty items (trailing commas allowed).
We read one row at a time and pass it for processing; the row is split at commas (ignoring empty lines), the items so obtained are braced and passed as arguments to the macro specified in the second argument to readcsv
. Such a macro should have the exact number of arguments as the columns in the CSV file.
I provide two examples.
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}
answered Jan 28 at 13:42
egregegreg
717k8719023197
717k8719023197
add a comment |
add a comment |
Here, I use readarray
to get the file into a def
and then listofitems
(included in readarray
) to parse it and loop over it.
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{\/,}%
readlistmylist{mydata}%
foreachitemxinmylist{%
deftmp{definecolor{tempcolor}{rgb}}%
expandafterexpandafterexpandaftertmpmylist[xcnt,1]%
textcolor{tempcolor}{mylist[xcnt,2]};%
}
end{document}
@ Steven B. Segletes I accepted Steven's code as answer due to its simplicity and its resistance to irregularity of CSV list (e.g. empty spaces or lines). Thank you all!
– Tony Tan
Jan 28 at 18:50
1
@TonyTan If you want surrounding spaces in the data to be ignored, you can change thereadlist
toreadlist*
. Then, leading/trailing blanks are excised from the parsed data.
– Steven B. Segletes
Jan 28 at 19:35
Is there easy way to assignmylist[xcnt,2]
tocol
andmylist[xcnt,1]
tocode
in foreach statement as I did in my original post? or even better, can I put the header in the CSV file? I can not find a clue from the readarray manual.
– Tony Tan
Jan 28 at 20:39
@TonyTan Let me think about your request, but perhaps look at thelistofitems
manual as well: ctan.org/pkg/listofitems
– Steven B. Segletes
Jan 28 at 20:55
1
@TonyTan If your own answer is not a duplicate of others, post away. Inlistofitems
, the way to skip the header isforeachitemxin<listname>{ifnumxcnt=1else...<your loop code here>...fi}
– Steven B. Segletes
Jan 29 at 2:38
|
show 2 more comments
Here, I use readarray
to get the file into a def
and then listofitems
(included in readarray
) to parse it and loop over it.
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{\/,}%
readlistmylist{mydata}%
foreachitemxinmylist{%
deftmp{definecolor{tempcolor}{rgb}}%
expandafterexpandafterexpandaftertmpmylist[xcnt,1]%
textcolor{tempcolor}{mylist[xcnt,2]};%
}
end{document}
@ Steven B. Segletes I accepted Steven's code as answer due to its simplicity and its resistance to irregularity of CSV list (e.g. empty spaces or lines). Thank you all!
– Tony Tan
Jan 28 at 18:50
1
@TonyTan If you want surrounding spaces in the data to be ignored, you can change thereadlist
toreadlist*
. Then, leading/trailing blanks are excised from the parsed data.
– Steven B. Segletes
Jan 28 at 19:35
Is there easy way to assignmylist[xcnt,2]
tocol
andmylist[xcnt,1]
tocode
in foreach statement as I did in my original post? or even better, can I put the header in the CSV file? I can not find a clue from the readarray manual.
– Tony Tan
Jan 28 at 20:39
@TonyTan Let me think about your request, but perhaps look at thelistofitems
manual as well: ctan.org/pkg/listofitems
– Steven B. Segletes
Jan 28 at 20:55
1
@TonyTan If your own answer is not a duplicate of others, post away. Inlistofitems
, the way to skip the header isforeachitemxin<listname>{ifnumxcnt=1else...<your loop code here>...fi}
– Steven B. Segletes
Jan 29 at 2:38
|
show 2 more comments
Here, I use readarray
to get the file into a def
and then listofitems
(included in readarray
) to parse it and loop over it.
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{\/,}%
readlistmylist{mydata}%
foreachitemxinmylist{%
deftmp{definecolor{tempcolor}{rgb}}%
expandafterexpandafterexpandaftertmpmylist[xcnt,1]%
textcolor{tempcolor}{mylist[xcnt,2]};%
}
end{document}
Here, I use readarray
to get the file into a def
and then listofitems
(included in readarray
) to parse it and loop over it.
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{\/,}%
readlistmylist{mydata}%
foreachitemxinmylist{%
deftmp{definecolor{tempcolor}{rgb}}%
expandafterexpandafterexpandaftertmpmylist[xcnt,1]%
textcolor{tempcolor}{mylist[xcnt,2]};%
}
end{document}
answered Jan 28 at 14:55
Steven B. SegletesSteven B. Segletes
154k9195403
154k9195403
@ Steven B. Segletes I accepted Steven's code as answer due to its simplicity and its resistance to irregularity of CSV list (e.g. empty spaces or lines). Thank you all!
– Tony Tan
Jan 28 at 18:50
1
@TonyTan If you want surrounding spaces in the data to be ignored, you can change thereadlist
toreadlist*
. Then, leading/trailing blanks are excised from the parsed data.
– Steven B. Segletes
Jan 28 at 19:35
Is there easy way to assignmylist[xcnt,2]
tocol
andmylist[xcnt,1]
tocode
in foreach statement as I did in my original post? or even better, can I put the header in the CSV file? I can not find a clue from the readarray manual.
– Tony Tan
Jan 28 at 20:39
@TonyTan Let me think about your request, but perhaps look at thelistofitems
manual as well: ctan.org/pkg/listofitems
– Steven B. Segletes
Jan 28 at 20:55
1
@TonyTan If your own answer is not a duplicate of others, post away. Inlistofitems
, the way to skip the header isforeachitemxin<listname>{ifnumxcnt=1else...<your loop code here>...fi}
– Steven B. Segletes
Jan 29 at 2:38
|
show 2 more comments
@ Steven B. Segletes I accepted Steven's code as answer due to its simplicity and its resistance to irregularity of CSV list (e.g. empty spaces or lines). Thank you all!
– Tony Tan
Jan 28 at 18:50
1
@TonyTan If you want surrounding spaces in the data to be ignored, you can change thereadlist
toreadlist*
. Then, leading/trailing blanks are excised from the parsed data.
– Steven B. Segletes
Jan 28 at 19:35
Is there easy way to assignmylist[xcnt,2]
tocol
andmylist[xcnt,1]
tocode
in foreach statement as I did in my original post? or even better, can I put the header in the CSV file? I can not find a clue from the readarray manual.
– Tony Tan
Jan 28 at 20:39
@TonyTan Let me think about your request, but perhaps look at thelistofitems
manual as well: ctan.org/pkg/listofitems
– Steven B. Segletes
Jan 28 at 20:55
1
@TonyTan If your own answer is not a duplicate of others, post away. Inlistofitems
, the way to skip the header isforeachitemxin<listname>{ifnumxcnt=1else...<your loop code here>...fi}
– Steven B. Segletes
Jan 29 at 2:38
@ Steven B. Segletes I accepted Steven's code as answer due to its simplicity and its resistance to irregularity of CSV list (e.g. empty spaces or lines). Thank you all!
– Tony Tan
Jan 28 at 18:50
@ Steven B. Segletes I accepted Steven's code as answer due to its simplicity and its resistance to irregularity of CSV list (e.g. empty spaces or lines). Thank you all!
– Tony Tan
Jan 28 at 18:50
1
1
@TonyTan If you want surrounding spaces in the data to be ignored, you can change the
readlist
to readlist*
. Then, leading/trailing blanks are excised from the parsed data.– Steven B. Segletes
Jan 28 at 19:35
@TonyTan If you want surrounding spaces in the data to be ignored, you can change the
readlist
to readlist*
. Then, leading/trailing blanks are excised from the parsed data.– Steven B. Segletes
Jan 28 at 19:35
Is there easy way to assign
mylist[xcnt,2]
to col
and mylist[xcnt,1]
to code
in foreach statement as I did in my original post? or even better, can I put the header in the CSV file? I can not find a clue from the readarray manual.– Tony Tan
Jan 28 at 20:39
Is there easy way to assign
mylist[xcnt,2]
to col
and mylist[xcnt,1]
to code
in foreach statement as I did in my original post? or even better, can I put the header in the CSV file? I can not find a clue from the readarray manual.– Tony Tan
Jan 28 at 20:39
@TonyTan Let me think about your request, but perhaps look at the
listofitems
manual as well: ctan.org/pkg/listofitems– Steven B. Segletes
Jan 28 at 20:55
@TonyTan Let me think about your request, but perhaps look at the
listofitems
manual as well: ctan.org/pkg/listofitems– Steven B. Segletes
Jan 28 at 20:55
1
1
@TonyTan If your own answer is not a duplicate of others, post away. In
listofitems
, the way to skip the header is foreachitemxin<listname>{ifnumxcnt=1else...<your loop code here>...fi}
– Steven B. Segletes
Jan 29 at 2:38
@TonyTan If your own answer is not a duplicate of others, post away. In
listofitems
, the way to skip the header is foreachitemxin<listname>{ifnumxcnt=1else...<your loop code here>...fi}
– Steven B. Segletes
Jan 29 at 2:38
|
show 2 more comments
After playing with it for a while, I think that datatool is a better tool for what I need. Thanks everyone for helping!
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:
expandafterexpandafterdefinecolor{tempcolor}{rgb}{code}
textcolor{tempcolor}{text}
}
end{document}
add a comment |
After playing with it for a while, I think that datatool is a better tool for what I need. Thanks everyone for helping!
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:
expandafterexpandafterdefinecolor{tempcolor}{rgb}{code}
textcolor{tempcolor}{text}
}
end{document}
add a comment |
After playing with it for a while, I think that datatool is a better tool for what I need. Thanks everyone for helping!
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:
expandafterexpandafterdefinecolor{tempcolor}{rgb}{code}
textcolor{tempcolor}{text}
}
end{document}
After playing with it for a while, I think that datatool is a better tool for what I need. Thanks everyone for helping!
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:
expandafterexpandafterdefinecolor{tempcolor}{rgb}{code}
textcolor{tempcolor}{text}
}
end{document}
answered Jan 29 at 0:22
Tony TanTony Tan
1237
1237
add a comment |
add a comment |
Thanks for contributing an answer to TeX - LaTeX Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f472182%2fuse-foreach-to-read-columns-from-a-csv-file%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown