我想根据是否存在非零数据点(对于此示例,\DepthOne
并且\DepthThree
需要进行测试)有条件地在报告中打印一些内容。
我首先使用 从 csv 表中读取值\csvreader
,然后使用 为这些值分配标签\newcommand
。然后使用 对标签进行测试\ifnum
。下面实现中的行为不是我所希望的。例如,我missing number, treated as zero
在句子前面得到了错误和奇怪的输出。此外,奇怪的是,我分配的标签之一(\SampleName
)似乎没有持续存在。
我是否可以完成我所尝试的事情?正确的方法是什么?
\documentclass[10pt]{report}
\usepackage{csvsimple}
\usepackage{filecontents}
\newcommand*{\ThisRock}{examplecsv}
% Make up some data in a CSV file called examplecsv.csv
\begin{filecontents*}{\ThisRock.csv}
SampleName,Depth1,DepthTwo,Depth3
ROCK001,48,52,0
\end{filecontents*}
% Pick out specific data in the file and create labels for them to be read by latex
\newcommand*{\SampleName}{\csvreader{\ThisRock.csv}{1=\SampleName}{\SampleName}}
\newcommand*{\DepthOne}{\csvreader{\ThisRock.csv}{2=\Depth1}{\Depth1}}
\newcommand*{\DepthTwo}{\csvreader{\ThisRock.csv}{3=\DepthTwo}{\DepthTwo}}
\newcommand*{\DepthThree}{\csvreader{\ThisRock.csv}{4=\Depth3}{\Depth3}}
\begin{document}
% Show the data (normally this is underwater)
\csvautotabular{examplecsv.csv} \\
% Expect this to print the sentence twice fully (first time is okay, second time incomplete?)
The rock sampled was called \SampleName. \\
The rock sampled was called \SampleName. \\
% Because there is some non-zero data for the first sample, expect this to print the sentence
\ifnum\ifnum\DepthOne>0 1\else0\fi
=1 %
\noindent The first sample hole was drilled to \DepthOne~mm\\
\else
\\
\fi
% Because the data is zero for the third sample, expect this not to print the sentence
\ifnum\ifnum\DepthThree>0 1\else0\fi
=1 %
\noindent The third sample hole was drilled to \DepthThree~mm\\
\else
\\
\fi
\end{document}
答案1
这个答案实际上指的是你的评论egreg 的回答:
当我希望访问上下文\samplename
之外的标签时会发生什么\csvreader
?
您可以使用\csvreader
上下文进行全局分配后充分扩展局部“变量”/宏——为了获得值,“变量”需要扩展两次:
% Make up some data in a CSV file
\begin{filecontents*}{\jobname.csv}
SampleName,Depth1,DepthTwo,Depth3
ROCK001,48,52,0
ROCK002,1,2,3
\end{filecontents*}
\documentclass[10pt]{report}
\usepackage{csvsimple}
\newcount\Samplenumber
\newcommand*\GlobalSamplename{}%
\newcommand*\GlobalDepthone{}%
\newcommand*\GlobalDepthtwo{}%
\newcommand*\GlobalDepththree{}%
%
\newcommand*\GlobalSamplenamederrorefault{\texttt{??}}%
\newcommand*\GlobalDepthoneerrorefault{0}%
\newcommand*\GlobalDepthtwoerrorefault{0}%
\newcommand*\GlobalDepththreeerrorefault{0}%
%
\newcommand\PassFirstToSecond[2]{#2{#1}}%
\newcommand\expandtwice{}%
\long\def\expandtwice#1#{\innerexpandtwice{#1}}%
\newcommand\innerexpandtwice[2]{%
\expandafter\expandafter\expandafter\PassFirstToSecond
\expandafter\expandafter\expandafter{#2}{#1}%
}%
\makeatletter
\newcommand\ReadToMacrosSampleDataRowNumber[1]{%
\@bsphack
\begingroup
\let\GlobalSamplename=\UndEfINeD
\Samplenumber=0 %
\csvreader{\jobname.csv}{%
SampleName=\InsideCsvreaderSamplename,
Depth1=\InsideCsvreaderDepthone,
DepthTwo=\InsideCsvreaderDepthtwo,
Depth3=\InsideCsvreaderDepththree,
}{%
\advance\Samplenumber by 1\relax
%
\ifnum#1=\Samplenumber\relax
\expandtwice\gdef\GlobalSamplename{\InsideCsvreaderSamplename}%
\expandtwice\gdef\GlobalDepthone{\InsideCsvreaderDepthone}%
\expandtwice\gdef\GlobalDepthtwo{\InsideCsvreaderDepthtwo}%
\expandtwice\gdef\GlobalDepththree{\InsideCsvreaderDepththree}%
\fi
}%
\ifx\GlobalSamplename\UndEfINeD
\@latex@error{Row #1 not available}{Seems your sheet of csv data does not have #1 rows.}%
\global\let\GlobalSamplename=\GlobalSamplenamederrorefault
\global\let\GlobalDepthone=\GlobalDepthoneerrorefault
\global\let\GlobalDepthtwo=\GlobalDepthtwoerrorefault
\global\let\GlobalDepththree=\GlobalDepththreeerrorefault
\fi
\endgroup
\@esphack
}%
\makeatother
\begin{document}
\noindent\csvautotabular{\jobname.csv}
\bigskip
Reading data row number 2 via
\verb|\ReadToMacrosSampleDataRowNumber{2}| and
using placeholder-macros outside
\verb|\csvreader|:\ReadToMacrosSampleDataRowNumber{2}
The rock sampled was called \GlobalSamplename.
The rock sampled was called \GlobalSamplename.
\ifnum\GlobalDepthone>0 %
The first sample hole was drilled to \GlobalDepthone~mm.
\fi
\ifnum\GlobalDepthtwo>0 %
The second sample hole was drilled to \GlobalDepthtwo~mm.
\fi
\ifnum\GlobalDepththree>0 %
The third sample hole was drilled to \GlobalDepththree~mm.
\fi
\noindent\hrulefill\null
Reading data row number 1 via
\verb|\ReadToMacrosSampleDataRowNumber{1}| and
using placeholder-macros outside
\verb|\csvreader|:\ReadToMacrosSampleDataRowNumber{1}
The rock sampled was called \GlobalSamplename.
The rock sampled was called \GlobalSamplename.
\ifnum\GlobalDepthone>0 %
The first sample hole was drilled to \GlobalDepthone~mm.
\fi
\ifnum\GlobalDepthtwo>0 %
The second sample hole was drilled to \GlobalDepthtwo~mm.
\fi
\ifnum\GlobalDepththree>0 %
The third sample hole was drilled to \GlobalDepththree~mm.
\fi
\noindent\hrulefill\null
Reading non-existing data row number 3 via
\verb|\ReadToMacrosSampleDataRowNumber{3}| and
using placeholder-macros outside
\verb|\csvreader|---this yields an error-message and
errordefault-values:\ReadToMacrosSampleDataRowNumber{3}
The rock sampled was called \GlobalSamplename.
The rock sampled was called \GlobalSamplename.
\verb|\GlobalSamplename| is assigned the errordefault value \GlobalSamplename.
\verb|\GlobalDepthone| is assigned the errordefault value \GlobalDepthone.
\verb|\GlobalDepthtwo| is assigned the errordefault value \GlobalDepthtwo.
\verb|\GlobalDepththree| is assigned the errordefault value \GlobalDepththree.
\ifnum\GlobalDepthone>0 %
The first sample hole was drilled to \GlobalDepthone~mm.
\fi
\ifnum\GlobalDepthtwo>0 %
The second sample hole was drilled to \GlobalDepthtwo~mm.
\fi
\ifnum\GlobalDepththree>0 %
The third sample hole was drilled to \GlobalDepththree~mm.
\fi
\end{document}
答案2
根据 @egreg 的建议,我做了更多研究,我发现我可以使用 datatool 来做我想做的事情:
\begin{filecontents*}{rockdata.csv}
SampleName,Depth1,DepthTwo,Depth3
ROCK001,48,52,0
\end{filecontents*}
\documentclass[10pt]{report}
\usepackage{datatool}
\DTLloaddb{rocks}{rockdata.csv}
\begin{document}
% This replaces the \newcommand step
\DTLforeach*{rocks}% database label
{\SampleName=SampleName,\DepthOne=Depth1,\DepthTwo=DepthTwo,\DepthThree=Depth3}% Assignment
{}% Things can be done in here
% But things can also seemingly be done out here too
\noindent The rock sampled was called \SampleName.\\
\dtlifnumeq{\DepthOne}{0}{\\}{The first sample hole was drilled to \DepthOne~mm\\}
\dtlifnumeq{\DepthTwo}{0}{\\}{The second sample hole was drilled to \DepthTwo~mm\\}
\dtlifnumeq{\DepthThree}{0}{\\}{The third sample hole was drilled to \DepthThree~mm\\}
\end{document}
更多大师方式
最终,我可以将丑陋的数据收集机制分离到样式文件中,并使用数据工具创建的标签来运行我想要的条件测试:
LaTex 文件:
\begin{filecontents*}{rockdata.csv}
SampleName,Depth1,DepthTwo,Depth3
ROCK001,48,52,0
\end{filecontents*}
\documentclass[10pt]{report}
\usepackage{datatool}
% User-defined package here
\usepackage{LoadRocks}
\begin{document}
% But things can also seemingly be done out here too
\noindent The rock sampled was called \SampleName.\\
\dtlifnumeq{\DepthOne}{0}{\\}{The first sample hole was drilled to \DepthOne~mm\\}
\dtlifnumeq{\DepthTwo}{0}{\\}{The second sample hole was drilled to \DepthTwo~mm\\}
\dtlifnumeq{\DepthThree}{0}{\\}{The third sample hole was drilled to \DepthThree~mm\\}
\end{document}
样式文件LoadRocks.sty
:
\ProvidesPackage{LoadRocks}[]
\DTLloaddb{rocks}{rockdata.csv}
\DTLforeach*{rocks}% database label
{\SampleName=SampleName,\DepthOne=Depth1,\DepthTwo=DepthTwo,\DepthThree=Depth3}% Assignment
{}
答案3
您误解了它\csvreader
的作用。
% Make up some data in a CSV file
\begin{filecontents*}{\jobname.csv}
SampleName,Depth1,DepthTwo,Depth3
ROCK001,48,52,0
ROCK002,1,2,3
\end{filecontents*}
\documentclass[10pt]{report}
\usepackage{csvsimple}
\begin{document}
\csvautotabular{\jobname.csv}
\bigskip
\csvreader{\jobname.csv}{
SampleName=\samplename,
Depth1=\depthone,
DepthTwo=\depthtwo,
Depth3=\depththree,
}
{%
The rock sampled was called \samplename.
The rock sampled was called \samplename.
\ifnum\depthone>0
The first sample hole was drilled to \depthone~mm
\fi
\ifnum\depththree>0
The third sample hole was drilled to \depththree~mm
\fi
\bigskip
}
\end{document}
如果您希望在文档的任何位置提供所有数据,则必须对行进行索引。
% Make up some data in a CSV file
\begin{filecontents*}{\jobname.csv}
SampleName,Depth1,DepthTwo,Depth3
ROCK001,48,52,0
ROCK002,1,2,3
\end{filecontents*}
\documentclass{article}
\usepackage{csvsimple}
\usepackage{xparse}
\usepackage{siunitx}
\ExplSyntaxOn
\NewDocumentCommand{\rocks}{m}
{
\csvreader{#1}{}
{
\int_gincr:N \g_fejoia_rocks_int
\prop_new:c { g_fejoia_rocks_ \int_to_arabic:n { \g_fejoia_rocks_int } _prop }
\prop_gput:cno
{ g_fejoia_rocks_ \int_to_arabic:n { \g_fejoia_rocks_int } _prop }
{ SampleName } { \csvcoli }
\prop_gput:cno
{ g_fejoia_rocks_ \int_to_arabic:n { \g_fejoia_rocks_int } _prop }
{ DepthOne } { \csvcolii }
\prop_gput:cno
{ g_fejoia_rocks_ \int_to_arabic:n { \g_fejoia_rocks_int } _prop }
{ DepthTwo } { \csvcoliii }
\prop_gput:cno
{ g_fejoia_rocks_ \int_to_arabic:n { \g_fejoia_rocks_int } _prop }
{ DepthThree } { \csvcoliv }
}
}
\int_new:N \g_fejoia_rocks_int
\DeclareExpandableDocumentCommand{\getrock}{mm}
{
\prop_item:cn { g_fejoia_rocks_#1_prop } { #2 }
}
\ExplSyntaxOff
\rocks{\jobname.csv}
\begin{document}
\csvautotabular{\jobname.csv}
\bigskip
\section{First rock}
The rock sampled was called \getrock{1}{SampleName}.
\ifnum\getrock{1}{DepthOne}>0
The first sample hole was drilled to \SI{\getrock{1}{DepthOne}}{\mm}
\fi
\ifnum\getrock{1}{DepthThree}>0
The third sample hole was drilled to \SI{\getrock{1}{DepthThree}}{\mm}
\fi
\section{Second rock}
The rock sampled was called \getrock{2}{SampleName}.
\ifnum\getrock{2}{DepthOne}>0
The first sample hole was drilled to \SI{\getrock{2}{DepthOne}}{\mm}
\fi
\ifnum\getrock{2}{DepthThree}>0
The third sample hole was drilled to \SI{\getrock{2}{DepthThree}}{\mm}
\fi
\end{document}