我想在表格标题中使用一些通过 csvsimple 导入的数据。
\begin{filecontents*}{data.csv}
column1,column2,column3
name1,val1a,val1b
name2,val2a,val2b
\end{filecontents*}
\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage{csvsimple}
\newcommand{\csvget}[3]{\csvreader[no head, filter equal={\thecsvinputline}{#2}]{#1}{}{#3}}
\begin{document}
\listoftables
\begin{table}
\centering
My Tabular
\caption{A caption \csvget{data.csv}{2}{\csvcolii}}
\end{table}
\end{document}
使用上面的代码我收到一个错误,如有Argument of \@caption has an extra...
什么建议吗?
提前感谢
CX
答案1
这是脆弱命令的一个问题。请参阅脆弱命令和坚固命令之间有什么区别?
使用 e-tex 兼容编译器,您可以\newrobustcmd
使用etoolbox
:
\begin{filecontents*}{data.csv}
column1,column2,column3
name1,val1a,val1b
name2,val2a,val2b
\end{filecontents*}
\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage{csvsimple}
\usepackage{etoolbox}
\newrobustcmd{\csvget}[3]{\csvreader[no head, filter equal={\thecsvinputline}{#2}]{#1}{}{#3}}
\begin{document}
\listoftables
\begin{table}
\centering
\csvautotabular{data.csv}
\caption{A caption \csvget{data.csv}{2}{\protect\csvcolii}}
\end{table}
\end{document}
如果没有它你可以使用\DeclareRobustCommand
\begin{filecontents*}{data.csv}
column1,column2,column3
name1,val1a,val1b
name2,val2a,val2b
\end{filecontents*}
\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage{csvsimple}
\DeclareRobustCommand{\csvget}[3]{\csvreader[no head, filter equal={\thecsvinputline}{#2}]{#1}{}{#3}}
\begin{document}
\listoftables
\begin{table}
\centering
\csvautotabular{data.csv}
\caption{A caption \csvget{data.csv}{2}{\protect\csvcolii}}
\end{table}
\end{document}
结果是:
答案2
编辑 (2017):代码已损坏,因为xint 1.1 (2014/10/28)
从那时起包xint
就不会加载。因此,这里需要一个xinttools
而不是。\usepackage{xint}
\usepackage{xinttools}
这是一些通用的 csv 文件处理宏\ReadCSVfile {filename}\to \MACRO
。然后\MACRO {i}{j}
扩展到第 行j
的第 项i
,您可以在 或任何其他方式中执行所有操作\caption
。文件名必须带有扩展名。
代码依赖于信特这些最近才被移到包中。但由于一些疏忽xinttools
,仍然至少有一个依赖项,因此我们在此处加载。xinttools
xint
xint
\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage{filecontents}
\begin{filecontents*}{data.csv}
column1,column2,column3
name1,val1a,val1b
name2,val2a,val2b
\end{filecontents*}
\usepackage{xinttools}
% VERY SIMPLE CSV HANDLING. Syntax:
% \ReadCSVfile {data.csv} \to \DATA
% \DATA WILL BE DEFINED AS A TWO ARGUMENTS COMMAND:
% \DATA {0}{0}: number of lines
% \DATA {i}{0}: number of items in i th line
% \DATA {i}{j}: j th item of i th line
% \DATA {0}{i}: the ith line as a list of braced items.
% WARNING: \DATA (or whatever it is called) WILL BE OVERWRITTEN.
\makeatletter
% example \ReadCSVfile {data.csv} \to \DATA
% WARNING: macro \DATA gets defined with no check if it already exists !!
\newcount\ReadCSV@linecount
\newcount\ReadCSV@itemcount
\newcommand\ReadCSVfile [3]{%
\IfFileExists{#1}
{%
\edef\ReadCSV@restore{\endlinechar=\the\endlinechar\relax
\catcode`\noexpand\@=\the\catcode`\@\relax}%
\endlinechar=-1
\makeatletter % in case csv file contains LaTeX macros with @ character
\newread\ReadCSV@instream
\openin\ReadCSV@instream\@filef@und
\ReadCSV@linecount\z@
\xintloop
\read\ReadCSV@instream to\ReadCSV@oneline
\unless\ifeof\ReadCSV@instream
\advance\ReadCSV@linecount\@ne
\ReadCSV@itemcount\z@
% we suppress all spaces around commas from the input file. Use braces around
% the item with spaces to force such spaces.
%
% the reason for such definition is for optimization in order for the conversion
% from CSV format to be done only once. We take care not to expand the file
% contents, in case they have some LaTeX meaning.
%
\toks@ \expandafter{\romannumeral0\expandafter\xintcsvtolist
\expandafter{\expandafter\space\ReadCSV@oneline}}%
\expandafter
\edef\csname CSV@\string#3@0.\the\ReadCSV@linecount\endcsname
{\the\toks@}%
\xintFor* ####1 in {\the\toks@} \do
{%
\advance\ReadCSV@itemcount\@ne
\expandafter
\def\csname CSV@\string#3@\the\ReadCSV@linecount.%
\the\ReadCSV@itemcount\endcsname
{####1}%
}%
\expandafter
\def\csname CSV@\string#3@\the\ReadCSV@linecount.%
0\expandafter\endcsname
\expandafter{\the\ReadCSV@itemcount}%
\repeat
\closein\ReadCSV@instream
\ReadCSV@restore
\expandafter
\edef\csname CSV@\string#[email protected]\endcsname {\the\ReadCSV@linecount}%
\def#3####1####2%
{\csname CSV@\string#3@\the\numexpr####1.\the\numexpr####2\endcsname }%
}
{\typeout{No file #1}}%
}
\ReadCSVfile {data.csv} \to \DATA
% \DATA {0}{0}: number of lines
% \DATA {i}{0}: number of items in i th line
% \DATA {i}{j}: j th item of i th line
% \DATA {0}{i}: the ith line as a list of *braced* items.
% spaces around commas in input file are REMOVED.
\begin{document}
\listoftables
\bigskip
\begin{table}
\centering
My Tabular
\caption{Second of second line \DATA {2}{2}}
\end{table}
\begin{table}
\centering
My Tabular
\caption{Third of first line \DATA {1}{3}}
\end{table}
The data file contains \DATA {0}{0} lines.
\newcounter{linecount}
\setcounter{linecount}{0}
% Note: we must use \endgraf because \xintloop currently does not accept \par.
\xintloop
\stepcounter{linecount}
The line numbered \arabic{linecount} contains \DATA {\value{linecount}}{0}
entries. Here they are:%
\xintFor* #1 in {\xintSeq {1}{\DATA {\value{linecount}}{0}}}
\do
{ \DATA {\value{linecount}}{#1},} and that's
it for that line.\endgraf
\ifnum\value{linecount}<\DATA{0}{0}
\repeat
\bigskip
We can also handle files with lines of different lengths.
\begin{filecontents*}{data2.csv}
column1,column2,column3,column4
name1,val1a,val1b
name2,val2a,val2b,X,Y,Z
a,b,c,d,e,f,g
\end{filecontents*}
\ReadCSVfile {data2.csv} \to \DATAII
\setcounter{linecount}{0}
% Note: we must use \endgraf because \xintloop currently does not accept \par.
\xintloop
\stepcounter{linecount}
The line numbered \arabic{linecount} contains \DATAII {\value{linecount}}{0}
entries. Here they are:
\xintListWithSep{, }{\DATAII {0}{\value{linecount}}}.\endgraf
\ifnum\value{linecount}<\DATAII {0}{0}
\repeat
\setcounter{linecount}{0}
Here is a nice Plain \TeX{} alignment with this data:
\tabskip1em
\fbox{\vbox{\halign{&\hfil#\hfil\cr
\xintloop
\ifnum\value{linecount}<\DATAII {0}{0}
\stepcounter{linecount}%
\xintListWithSep {&}{\DATAII {0}{\value{linecount}}}%
\cr
\repeat
}}}
\medskip \LaTeX{}'s tabulars can be used with lines
having a varying number of items but one must know the maximal number of items
from all rows (I think).
\end{document}