我想定义新命令并能够更改 csv 文件的输出。假设 csv 文件以分号分隔:
Name; Score
Max; 12
Peter; 32
Anna; 27
现在我想要在 LaTeX 中实现以下内容:
\newcommand{\Max}{12}
\newcommand{\Peter}{32}
\newcommand{\Anna}{27}
1. 基本解决方案:仅应从 csv 文件中读取数字(= 12
、32
和)。命令名称(= 、和)可以硬编码。27
\Max
\Peter
\Anna
2. 高级解决方案:循环遍历 csv 文件的所有行(可选:从第二行开始)并根据第一列中的名称(= 命令名称)和第二列中的分数(= 每个命令名称的期望输出)创建新命令。
我如何实现上述任何解决方案?有很多读取 csv 文件并在 LaTeX 中从中创建表格的示例,但我没有找到任何可以解决我的问题的方法。
提前致谢!
更新:添加了受以下网站启发的最小工作示例(MWE): https://www.uweziegenhagen.de/?p=3100
以下代码循环遍历我的 csv 文件并给出姓名和分数。这不能解决我的问题,但可能是其中的一部分:
\documentclass{article}
\usepackage{datatool}
\DTLsetseparator{;}
\DTLloaddb{scores}{test.csv}
\begin{document}
\DTLforeach{scores}{%
\name=Name,\score=Score}{%
\name\score\\}
\end{document}
现在,当我尝试解决我的问题时,我无法以编程方式添加新命令名称(\Max
、\Peter
和\Anna
)。我收到错误:Command \textbackslash already defined. \newcommand{\textbackslash \name}{\score}}
。如果这可行,那将是“高级解决方案”,这将非常好:
\documentclass{article}
\usepackage{datatool}
\DTLsetseparator{;}
\DTLloaddb{scores}{test.csv}
\DTLforeach{scores}{%
\name=Name,\score=Score}{%
\newcommand{\textbackslash \name}{\score}}
\begin{document}
\Max
\Peter
\Anna
\end{document}
答案1
\documentclass{article}
\usepackage{readarray}
\begin{filecontents*}[overwrite]{mydata.txt}
Name; Score
Max; 12
Peter; 32
Anna; 27
\end{filecontents*}
\begin{document}
\readarraysepchar{,}
\setsepchar{,/;}
\readdef{mydata.txt}\datadef
\ignoreemptyitems
\readlist*\datarray{\datadef}
\foreachitem\z\in\datarray[]{%
\ifnum\zcnt=1\else
\expandafter\xdef\csname\datarray[\zcnt,1]\endcsname
{\datarray[\zcnt,2]}%
\fi
}
The score for Max is \Max.
But Peter, with a score of \Peter, beats him.
The person from line 4 in the file, whose name I can't remember,
is \datarray[4,1]. Her score is \datarray[4,2].
Oh, Anna? Great! I can just use \Anna.
\end{document}
答案2
这是不需要任何附加包的代码。仅使用 TeX 原语。
\documentclass{article}
\begin{document}
\def\readrow #1;#2;{\ifx^#2^\else
\expandafter\xdef\csname #1\endcsname{#2}%
\expandafter\readrow\fi}
\def\startread #1;#2;{\readrow} % skip first row
\begingroup
\endlinechar=`; \everyeof={;;} \catcode`\@=11
\expandafter \startread \@@input mydata.txt %
\endgroup %
The score for Max is \Max.
But Peter, with a score of \Peter, beats him.
I can just use \Anna.
\end{document}
答案3
您可以逐行读取文件(丢弃第一行),在分号处拆分行并执行定义:
\begin{filecontents*}{\jobname.dat}
Name; Score
Max; 12
Peter; 32
Anna; 27
\end{filecontents*}
\documentclass{article}
\ExplSyntaxOn
\NewDocumentCommand{\makecommands}{m}
{
\owmal_makecommands:n { #1 }
}
\ior_new:N \g_owmal_makecommands_ior
\seq_new:N \l__owmal_makecommands_line_seq
\cs_new_protected:Nn \owmal_makecommands:n
{
\ior_open:Nn \g_owmal_makecommands_ior { #1 }
\ior_get:NN \g_owmal_makecommands_ior \l_tmpa_tl % discard the first line
\ior_map_inline:Nn \g_owmal_makecommands_ior
{
\seq_set_split:Nnn \l__owmal_makecommands_line_seq { ; } { ##1 }
\cs_new:cpx
{ \seq_item:Nn \l__owmal_makecommands_line_seq { 1 } } % name of command
{ \seq_item:Nn \l__owmal_makecommands_line_seq { 2 } } % text
}
}
\ExplSyntaxOff
\makecommands{\jobname.dat}
\begin{document}
The score for Max is \Max
The score for Peter is \Peter
The score for Anna is \Anna
\end{document}
另一方面,您可以避免定义命令并将分数存储在按名称索引的属性列表中。
\begin{filecontents*}{\jobname.dat}
Name; Score
Max; 12
Peter; 32
Anna; 27
\end{filecontents*}
\documentclass{article}
\ExplSyntaxOn
\NewDocumentCommand{\readscores}{m}
{
\owmal_scores_read:n { #1 }
}
\NewExpandableDocumentCommand{\getscore}{m}
{
\prop_item:Nn \g_owmal_scores_prop { #1 }
}
\ior_new:N \g_owmal_scores_ior
\seq_new:N \l__owmal_scores_line_seq
\prop_new:N \g_owmal_scores_prop
\cs_new_protected:Nn \owmal_scores_read:n
{
\ior_open:Nn \g_owmal_scores_ior { #1 }
\ior_get:NN \g_owmal_scores_ior \l_tmpa_tl % discard the first line
\ior_map_inline:Nn \g_owmal_scores_ior
{
\seq_set_split:Nnn \l__owmal_scores_line_seq { ; } { ##1 }
\prop_gput:Nxx \g_owmal_scores_prop
{ \seq_item:Nn \l__owmal_scores_line_seq { 1 } } % name
{ \seq_item:Nn \l__owmal_scores_line_seq { 2 } } % score
}
}
\ExplSyntaxOff
\readscores{\jobname.dat}
\begin{document}
The score for Max is \getscore{Max}
The score for Peter is \getscore{Peter}
The score for Anna is \getscore{Anna}
\end{document}