use foreach to read columns from a csv file?












5















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}









share|improve this question





























    5















    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}









    share|improve this question



























      5












      5








      5


      0






      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}









      share|improve this question
















      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






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Jan 28 at 6:58









      Hafid Boukhoulda

      3,0921520




      3,0921520










      asked Jan 28 at 6:49









      Tony TanTony Tan

      1237




      1237






















          4 Answers
          4






          active

          oldest

          votes


















          3














          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}


          enter image description here






          share|improve this answer































            3














            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}


            enter image description here






            share|improve this answer































              3














              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}


              enter image description here






              share|improve this answer
























              • @ 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 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











              • @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





                @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



















              2














              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}


              enter image description here






              share|improve this answer























                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
                });


                }
                });














                draft saved

                draft discarded


















                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









                3














                As long as it is ensured that each line of your .csv-file is exactly of pattern



                {&langle;rgb-specification&rangle;},&langle;name of color&rangle;,



                and that there are no spaces at the commas that separate the {&langle;rgb-specification&rangle;} from the &langle;name of color&rangle;, 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}


                enter image description here






                share|improve this answer




























                  3














                  As long as it is ensured that each line of your .csv-file is exactly of pattern



                  {&langle;rgb-specification&rangle;},&langle;name of color&rangle;,



                  and that there are no spaces at the commas that separate the {&langle;rgb-specification&rangle;} from the &langle;name of color&rangle;, 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}


                  enter image description here






                  share|improve this answer


























                    3












                    3








                    3







                    As long as it is ensured that each line of your .csv-file is exactly of pattern



                    {&langle;rgb-specification&rangle;},&langle;name of color&rangle;,



                    and that there are no spaces at the commas that separate the {&langle;rgb-specification&rangle;} from the &langle;name of color&rangle;, 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}


                    enter image description here






                    share|improve this answer













                    As long as it is ensured that each line of your .csv-file is exactly of pattern



                    {&langle;rgb-specification&rangle;},&langle;name of color&rangle;,



                    and that there are no spaces at the commas that separate the {&langle;rgb-specification&rangle;} from the &langle;name of color&rangle;, 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}


                    enter image description here







                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Jan 28 at 12:06









                    Ulrich DiezUlrich Diez

                    4,500616




                    4,500616























                        3














                        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}


                        enter image description here






                        share|improve this answer




























                          3














                          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}


                          enter image description here






                          share|improve this answer


























                            3












                            3








                            3







                            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}


                            enter image description here






                            share|improve this answer













                            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}


                            enter image description here







                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered Jan 28 at 13:42









                            egregegreg

                            717k8719023197




                            717k8719023197























                                3














                                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}


                                enter image description here






                                share|improve this answer
























                                • @ 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 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











                                • @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





                                  @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
















                                3














                                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}


                                enter image description here






                                share|improve this answer
























                                • @ 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 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











                                • @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





                                  @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














                                3












                                3








                                3







                                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}


                                enter image description here






                                share|improve this answer













                                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}


                                enter image description here







                                share|improve this answer












                                share|improve this answer



                                share|improve this answer










                                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 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











                                • @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





                                  @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



















                                • @ 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 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











                                • @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





                                  @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

















                                @ 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











                                2














                                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}


                                enter image description here






                                share|improve this answer




























                                  2














                                  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}


                                  enter image description here






                                  share|improve this answer


























                                    2












                                    2








                                    2







                                    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}


                                    enter image description here






                                    share|improve this answer













                                    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}


                                    enter image description here







                                    share|improve this answer












                                    share|improve this answer



                                    share|improve this answer










                                    answered Jan 29 at 0:22









                                    Tony TanTony Tan

                                    1237




                                    1237






























                                        draft saved

                                        draft discarded




















































                                        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.




                                        draft saved


                                        draft discarded














                                        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





















































                                        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







                                        Popular posts from this blog

                                        How to change which sound is reproduced for terminal bell?

                                        Title Spacing in Bjornstrup Chapter, Removing Chapter Number From Contents

                                        Can I use Tabulator js library in my java Spring + Thymeleaf project?