4

I have a CSV file which looks like this

testa, 123
testb, 456
testc, 789

How can process the CSV file to get the following result?

\newcommand{\testa}{123}
\newcommand{\testb}{456}
\newcommand{\testc}{789}
5

enter image description here

\documentclass{article}

\newread\zz
\def\xpar{\par}
\def\zzdef#1,#2#3 \relax{\expandafter\def\csname#1\endcsname{#2#3}}
\openin\zz=zz.csv
\loop
\ifeof\zz
\else
\read\zz to \tmp
\ifx\tmp\xpar\else
\expandafter\zzdef\tmp\relax
\fi
\repeat
\begin{document}


 testa is [\testa]

 testb is [\testb]

 testc is [\testc]

\end{document}
5

You can process each line of the CSV using datatool's \DTLforeach processor and create a macro for each:

enter image description here

\documentclass{article}

\usepackage{filecontents}
\begin{filecontents*}{data.csv}
testa, 123
testb, 456
testc, 789
\end{filecontents*}

\usepackage{datatool}

\begin{document}

\DTLloaddb[noheader, keys={varname,datavalue}]{data}{data.csv}
\DTLforeach{data}{\varname=varname,\datavalue=datavalue}{%
  \expandafter\edef\csname\varname\endcsname{\datavalue}%
}

\verb|\testa|: \testa

\verb|\testb|: \testb

\verb|\testc|: \testc

\end{document}
  • \expandafter\edef\csname\varname\endcsname{\datavalue} is sufficient. Or \expandafter\def\csname\varname\expandafter\endcsname\expandafter{\datavalue} (safer). – egreg Jan 26 '18 at 0:18
4

With expl3:

\begin{filecontents*}{\jobname.csv}
testa, 123
testb, 456
testc, 789
\end{filecontents*}

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\definefromcsv}{m}
 {
  \schneider_definefromcsv:n { #1 }
 }

\cs_new_protected:Nn \schneider_definefromcsv:n
 {
  \ior_open:Nn \g_tmpa_ior { #1 }
  \ior_map_inline:Nn \g_tmpa_ior
   {
    \__schneider_define:n { ##1 }
   }
  \ior_close:N \g_tmpa_ior
 }
\cs_new_protected:Nn \__schneider_define:n
 {
  \clist_set:Nn \l_tmpa_clist { #1 }
  \cs_new:cpx { \clist_item:Nn \l_tmpa_clist { 1 } }
   {
    \clist_item:Nn \l_tmpa_clist { 2 }
   }
 }

\ExplSyntaxOff

\begin{document}

\definefromcsv{\jobname.csv}

\verb|\testa|: --\testa--

\verb|\testb|: --\testb--

\verb|\testc|: --\testc--

\end{document}

enter image description here

Some notes. With \ior_map_inline:Nn the trailing space is not removed, but \clist_set:Nn takes care of that, because it strips leading and trailing spaces around items when it normalizes the clist. The presence of “\edef dangerous” macros such as \textbf is not a problem, because \clist_item:Nn returns the item in “unexpandable form”, that is, surrounded by \exp_not:n (\unexpanded in eTeX lingo).

4

Just for completeness, a LuaTeX solution. Assuming you have the (name, definition) pairs in a file called foo.csv, put the following in a file called say define.lua:

for line in io.lines("foo.csv") do
   name, def = line:match("([^,]+), ([^,]+)")
   token.set_macro(name, def)
end

Then you can compile the below with lualatex:

\documentclass{article}
\directlua{dofile('define.lua')}
\begin{document}
Here we can say \testa, \testb, and \testc.
\end{document}

output

3

This is a slightly more intuitive version of Werner's answer (or David's) using datatool and etoolbox.

\RequirePackage{filecontents}
\begin{filecontents*}{\jobname.csv}
testa, 123
testb, 456
testc, 789
\end{filecontents*}
\documentclass{article}
\usepackage{etoolbox}
\usepackage{datatool}
\begin{document}
\DTLloaddb[noheader,keys={name,value}]{csnames}{\jobname.csv}
\DTLforeach*{csnames}{\myname=name,\myvalue=value}{
\csxdef{\myname}{\expandonce{\myvalue}}
}
\verb|\testa|: \testa

\verb|\testb|: \testb

\verb|\testc|: \testc
\end{document}

output of code

  • What if the first line is testa,\textbf{123}? ;-) Better doing\csxdef{\myname}{\expandonce{\myvalue}} – egreg Jan 26 '18 at 0:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.