将 csv 值读取为键值对

将 csv 值读取为键值对

我有一个包含以下内容的 csv 文件:

"N","n","M"
200,100,50

\N我怎样才能用 LaTeX 读取它,使得,\n_trees然后\M分别返回 200、100 和 50 ?或者其他一些内部名称,例如\myarray{N}\myarray{n}\myarray{M}任何其他允许我在文本中使用这些值的语法。

答案1

以下是用于存储和检索值的另一种 LaTeX3 属性列表。使用\ReadCSVArray{<file name>}读取.csv文件,然后使用\ArrayItem{<key>}检索<value>与键关联的。\ArrayItem是可扩展的,因此如果<value>是数字,那么您可以在 中使用数字表达式\fpeval(例如)。代码假定所有键都用双引号括起来。

在此处输入图片描述

\documentclass{article}
\begin{filecontents*}[overwrite]{mycsv.csv}
"N","n","M"
200,100,50
\end{filecontents*}
\usepackage{xparse}
\usepackage{xfp}
\ExplSyntaxOn
\ior_new:N \l__lrnv_temp_ior
\str_new:N \l__lrnv_tmp_str
\seq_new:N \l__lrnv_key_seq
\seq_new:N \l__lrnv_value_seq
\prop_new:N \l__lrnv_array_prop
\cs_new_protected:Npn \__lrnv_csv_to_prop:n #1
  {
    \__lrnv_input_csv:n {#1}
    \seq_mapthread_function:NNN \l__lrnv_key_seq \l__lrnv_value_seq
      \__lrnv_set_prop:nn
  }
\cs_new_protected:Npn \__lrnv_set_prop:nn #1 #2
  { \prop_put:Nnn \l__lrnv_array_prop {#1} {#2} }
\cs_new_protected:Npn \__lrnv_input_csv:n #1
  {
    \ior_open:Nn \l__lrnv_temp_ior {#1}
    \__lrnv_read_csv_row_to_seq:NN \l__lrnv_temp_ior \l__lrnv_key_seq
    \__lrnv_read_csv_row_to_seq:NN \l__lrnv_temp_ior \l__lrnv_value_seq
    \ior_close:N \l__lrnv_temp_ior
  }
\cs_new_protected:Npn \__lrnv_read_csv_row_to_seq:NN #1 #2
  {
    \ior_str_get:NN #1 \l__lrnv_tmp_str
    \seq_set_from_clist:NV #2 \l__lrnv_tmp_str
  }
\cs_generate_variant:Nn \seq_set_from_clist:Nn { NV }
\msg_new:nnn { lrnv } { file-not-found }
  { File~`#1'~not~found. }
\NewDocumentCommand \ReadCSVArray { m }
  {
    \file_if_exist:nTF {#1}
      { \__lrnv_csv_to_prop:n {#1} }
      { \msg_error:nnn { lrnv } { file-not-found } {#1} }
  }
\NewExpandableDocumentCommand \ArrayItem { m }
  { \prop_item:Nn \l__lrnv_array_prop { "#1" } }
\ExplSyntaxOff
\begin{document}
\ReadCSVArray{mycsv.csv}
$N=\ArrayItem{N}$, $n=\ArrayItem{n}$, and $M=\ArrayItem{M}$
(Total: \fpeval{\ArrayItem{N}+\ArrayItem{n}+\ArrayItem{M}}).
\end{document}

答案2

稍微(更紧凑)的版本expl3

\begin{filecontents*}{\jobname.csv}
"N","n","M"
200,100,50
\end{filecontents*}

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\readcsvfile}{m}
 {% #1 is the file name
  \lrnv_readcsvfile:n { #1 }
 }
\NewExpandableDocumentCommand{\getcsvitem}{m}
 {
  \prop_item:Nn \l__lrnv_readcsvfile_prop { #1 }
 }
\NewExpandableDocumentCommand{\getcsvitembynumber}{m}
 {
  \seq_item:Nn \l__lrnv_readcsvfile_body_seq { #1 }
 }

\ior_new:N \g__lrnv_readcsvfile_ior
\tl_new:N \l__lrnv_readcsvfile_tl
\seq_new:N \l__lrnv_readcsvfile_head_seq
\seq_new:N \l__lrnv_readcsvfile_body_seq
\prop_new:N \l__lrnv_readcsvfile_prop
\cs_generate_variant:Nn \prop_put:Nnn { Nnf }

\cs_new_protected:Nn \lrnv_readcsvfile:n
 {
  % open the file
  \ior_open:Nn \g__lrnv_readcsvfile_ior { #1 }
  % get the first line
  \ior_get:NN \g__lrnv_readcsvfile_ior \l__lrnv_readcsvfile_tl
  % remove the quotes
  \tl_replace_all:Nnn \l__lrnv_readcsvfile_tl { " } { }
  % populate a sequence splitting at commas
  \seq_set_split:NnV \l__lrnv_readcsvfile_head_seq { , } \l__lrnv_readcsvfile_tl
  % get the second line
  \ior_get:NN \g__lrnv_readcsvfile_ior \l__lrnv_readcsvfile_tl
  % populate the a sequence splitting at commas
  \seq_set_split:NnV \l__lrnv_readcsvfile_body_seq { , } \l__lrnv_readcsvfile_tl
  % close the file
  \ior_close:N \g__lrnv_readcsvfile_ior
  % clear the property list
  \prop_clear:N \l__lrnv_readcsvfile_prop
  % populate the property list: property from first sequence, value from second sequence
  \seq_indexed_map_inline:Nn \l__lrnv_readcsvfile_head_seq
   {
    \prop_put:Nnf \l__lrnv_readcsvfile_prop { ##2 } { \seq_item:Nn \l__lrnv_readcsvfile_body_seq { ##1 } }
   }
 }

\cs_new_protected:Nn \__lrnv_readcsvfile_read:
 {
 }

\ExplSyntaxOff

\begin{document}

\readcsvfile{\jobname.csv}

\getcsvitem{N} -- \getcsvitembynumber{1}

\getcsvitem{n} -- \getcsvitembynumber{2}

\getcsvitem{M} -- \getcsvitembynumber{3}

\end{document}

在此处输入图片描述

答案3

尽管已发布可接受的答案,但我还会提供使用 DataTool 的选项。我保持原始\DTLfetch命令暴露。它可以封装在自己的宏中以实现您的目标。

\documentclass{article}

% datatool does the database work
\usepackage{datatool}

% the file contents

\begin{filecontents*}{values.csv}
color, N, n_trees, M
red, 200, 100, 50
green, 300, 10, 49
blue, 400, 1, 48
\end{filecontents*}

% load the database to the document

\DTLloaddb{values}{values.csv}

\begin{document}

% examples

The trees for red is: \DTLfetch{values}{color}{red}{n_trees}.

The M for blue is: \DTLfetch{values}{color}{blue}{M}.

The color that had 1 tree is: \DTLfetch{values}{n_trees}{1}{color}.

\end{document}

另见另一个示例此链接

相关内容