如何从 csv 文件生成键值宏?

如何从 csv 文件生成键值宏?

我有一个包含键值对的 CSV 文件,我希望能够将该文件读入 latex,并生成宏来访问这些值。这是我目前的尝试datatool

\documentclass{article}
\usepackage{datatool,filecontents}

\newcommand{\loadmap}[2][map]{%
    \DTLloaddb{#1}{#2}%
    \DTLforeach{#1}{\Key=Key,\Value=Value}{%
        \expandafter\def\csname #1\Key\endcsname{\Value}}}

\newcommand{\loadmaptest}[2][map]{%
    \DTLloaddb{#1}{#2}%
    \DTLforeach{#1}{\Key=Key,\Value=Value}{\Key,\Value\\}}

\begin{document}
\begin{filecontents}{testdata.csv}
    Key,Value
    firstkey,0.002
    secondkey,1.0
    thirdkey,4
\end{filecontents}  

\loadmap{testdata.csv}
\mapfirstkey,\mapsecondkey,\mapthirdkey\\

\loadmaptest[second]{testdata.csv}

\end{document}

您将看到如下输出:

4,4,4
firstkey,0.002
secondkey,1.0
thirdkey,4

因此,虽然DTLforeach在直接显示结果时正确地遍历了 CSV 文件,但宏的生成是不正确的。特别是,它正确地生成了宏名称\mapfirstkey,如 等,但它们的值都是键中的最后一个值。我怀疑这与我错误地扩展宏有关……

有任何想法吗?

答案1

您必须扩展\Value,否则定义的宏将包含它而不是它的值。

如果您计划在键中使用非字母字符,我建议实施一个\usevar命令。

\begin{filecontents*}{\jobname.csv}
Key,Value
firstkey,0.002
secondkey,1.0
thirdkey,4
\end{filecontents*}

\documentclass{article}
\usepackage{datatool}

\newcommand{\loadmap}[2][map]{%
  \DTLloaddb{#1}{#2}%
  \DTLforeach{#1}{\Key=Key,\Value=Value}{%
    \expandafter\def\csname#1\Key\expandafter\endcsname\expandafter{\Value}%
  }%
}

\newcommand{\usevar}[2]{\csname #1#2\endcsname}

\begin{document}

\loadmap{\jobname.csv}

\usevar{map}{firstkey}, \usevar{map}{secondkey}, \usevar{map}{thirdkey}  

\end{document}

借助xparseexpl3,可以变得更加高效。

请注意,该\usevar命令可以使用可选参数,但它仍然完全可扩展。

\begin{filecontents*}{\jobname.csv}
Key,Value
firstkey,0.002
secondkey,1.0
thirdkey,4
\end{filecontents*}

\documentclass{article}
\usepackage{datatool}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\loadmap}{O{map}m}
 {
  \jlperla_keyvalue_assign:nn { #1 } { #2 }
 }
\NewExpandableDocumentCommand{\usevar}{O{map}m}
 {
  \prop_item:cn { l_jlperla_keyvalue_#1_prop } { #2 }
 }

\tl_new:N \l__jlperla_keyvalue_key_tl
\tl_new:N \l__jlperla_keyvalue_Value_tl

\cs_new_protected:Nn \jlperla_keyvalue_assign:nn
 {
  \prop_clear_new:c { l_jlperla_keyvalue_#1_prop }
  \DTLloaddb{#1}{#2}
  \DTLforeach{#1}
   {
    \l__jlperla_keyvalue_key_tl = Key,
    \l__jlperla_keyvalue_Value_tl = Value
   }
   {
    \prop_put:cVV
     { l_jlperla_keyvalue_#1_prop }
     \l__jlperla_keyvalue_key_tl
     \l__jlperla_keyvalue_Value_tl
   }
 }
\cs_generate_variant:Nn \prop_put:Nnn { cVV }
\ExplSyntaxOff

\begin{document}

\loadmap{\jobname.csv}

\usevar{firstkey}, \usevar[map]{secondkey}, \usevar{thirdkey}

\end{document}

在此处输入图片描述

答案2

替换\def\edef

\documentclass{article}
\usepackage{datatool,filecontents}

\newcommand{\loadmap}[2][map]{%
    \DTLloaddb{#1}{#2}%
    \DTLforeach{#1}{\Key=Key,\Value=Value}{%
        \expandafter\edef\csname #1\Key\endcsname{\Value}}}% <- changed

\newcommand{\loadmaptest}[2][map]{%
    \DTLloaddb{#1}{#2}%
    \DTLforeach{#1}{\Key=Key,\Value=Value}{\Key,\Value\\}}

\begin{document}
\begin{filecontents}{testdata.csv}
    Key,Value
    firstkey,0.002
    secondkey,1.0
    thirdkey,4
\end{filecontents}  

\loadmap{testdata.csv}
\noindent
\mapfirstkey,\mapsecondkey,\mapthirdkey\\
\loadmaptest[second]{testdata.csv}

\end{document}

结果:

在此处输入图片描述


因为有一条评论:虽然可以在键中使用数字,但您必须在代码中使用 `\csname ...\endcsname。所以我不建议使用以下示例。也许您可以为您的键找到更好的名称。

\documentclass{文章} \usepackage{数据工具,文件内容}

\newcommand{\loadmap}[2][map]{%
    \DTLloaddb{#1}{#2}%
    \DTLforeach{#1}{\Key=Key,\Value=Value}{%
        \expandafter\edef\csname #1\csname Key\endcsname\endcsname{\Value}}}

\newcommand{\loadmaptest}[2][map]{%
    \DTLloaddb{#1}{#2}%
    \DTLforeach{#1}{\Key=Key,\Value=Value}{\Key,\Value\\}}

\begin{document}
\begin{filecontents}{testdata.csv}
    Key,Value
    firstkey,0.002
    2key,1.0
    thirdkey,4
\end{filecontents}  

\loadmap{testdata.csv}
\noindent
\mapfirstkey,\csname map2key\endcsname ,\mapthirdkey\\
\loadmaptest[second]{testdata.csv}

\end{document}

结果:

在此处输入图片描述

答案3

readarray一种用 代替 的方法datatool

\documentclass{article}
\usepackage{readarray}[2016-11-07]
\usepackage{filecontents}
\begin{filecontents*}{myfile.dat}
    Key,Value
    firstkey,0.002
    secondkey,1.0
    thirdkey,4
    4key, 77
\end{filecontents*}
\newcounter{mycount}
\newcommand\assigndat[1]{%
  \readarraysepchar{,}%
  \readdef{#1}\mydata%
  \readarray*\mydata\myarray[-,\ncols]%
  \setcounter{mycount}{0}%
  \whiledo{\themycount<\nrows}{%
    \stepcounter{mycount}%
    \edef\tmp{\myarray[\themycount,1]}%
    \expandafter\expandafter\expandafter\xdef\expandafter\csname\tmp\endcsname{%
      \myarray[\themycount,2]}%
    }%
}
\newcommand\theKey[1]{\myarray[#1,1]}
\newcommand\theValue[1]{\csname #1\endcsname}
\begin{document}
\assigndat{myfile.dat}
\theKey{1}: \theValue{\theKey{1}} or \theValue{Key}\par
\theKey{2}: \theValue{\theKey{2}} or \theValue{firstkey}\par
\theKey{3}: \theValue{\theKey{3}} or \theValue{secondkey}\par
\theKey{4}: \theValue{\theKey{4}} or \theValue{thirdkey}\par
\theKey{5}: \theValue{\theKey{5}} or \theValue{4key}
\end{document}

在此处输入图片描述

加载包后pgffor,可以一次性循环遍历所有键,如下所示:

\foreach\x in {2,...,\myarrayROWS}{\theKey{\x}: \theValue{\theKey{\x}}\par}

相关内容