我有一个包含以下内容的 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}
另见另一个示例此链接。