我正在尝试学习如何使用\xappto
,并且一直在使用这个示例。为什么它不起作用?当我after row=\noexpand\midrule
直接传递\codeforpgf{}
时,它工作正常,但当我使用 时,出现了问题\xappto
。
\documentclass{article}
\RequirePackage{etoolbox}
\RequirePackage{pgfplotstable}
\RequirePackage{pgfplots}
\usepackage{booktabs}
\begin{filecontents*}{test.csv}
ColA, ColB, ColC
0.17, 0.91, 0.67
0.15, 0.17, 0.92
0.48, 0.1, 0.28
\end{filecontents*}
\def\buildTable#1{%
\def\temp{after row=\noexpand\midrule}%
\def\codeforpgf{}%
\expandafter\xappto\expandafter\codeforpgf\expandafter{\temp}%
\pgfplotstableread[col sep = comma]{#1}\rawdata%
\xdef\theTable{\noexpand\pgfplotstabletypeset[\codeforpgf]}%
\theTable{\rawdata}%
}%
\begin{document}
\begin{table}
\buildTable
{%CSV file
test.csv%
}
\end{table}
\end{document}
答案1
egreg 和 Ulrike Fisher 是对的。在我看来,这是一个不必要的复杂且危险的定义。\buildTable
可以写得更简单:
\def\buildTable#1{%
\pgfplotstableread[col sep = comma]{#1}\rawdata%
\pgfplotstabletypeset[after row=\midrule]{\rawdata}%
}%
但是您想了解\xappto
,因此这里解释了出了什么问题:
首先,你不需要所有的\expandafter
s,因为\xappto
会为你扩展\temp
。但这不是什么大问题,因为有了\expandafter
s 基本上就像写作\xappto\codeforpgf{after row=\noexpand\midrule}
一样。主要问题是 中的第二次扩展\xdef
。
当\noexpand
扩展时,它会将下一个标记(在您的情况下为\midrule
)复制回输入流而不进行扩展。此后,\noexpand
消失,它完成了工作。此扩展在 中完成\xappto
。因此,不要写成
\def\temp{after row=\noexpand\midrule}%
\def\codeforpgf{}%
\xappto\codeforpgf{\temp}%
你可以写
\def\codeforpgf{after row=\midrule}%
会产生同样的结果和同样的错误后者因为 now\xdef
会尝试扩展\midrule
到表之外,这不是一个好主意。
\def\codeforpgf{after row=\noexpand\midrule}%
将会\xdef
按预期工作。为了使\midrule
通过两个扩展的扩展不展开,必须编写
\def\temp{after row=\noexpand\noexpand\noexpand\midrule}%
在您的宏中,您也可以使用\appto
而不是 来\xappto
使其发挥作用。
在下面的代码中我插入了几个\show
s。\show\somemacro
将在日志文件中显示 的定义\somemacro
。例如,
\buildTableC
将写入
> \temp=macro:
->after row=\noexpand \noexpand \noexpand \midrule .
到日志中。通过这个你可以看到\noexpand
s 是如何消失的。搜索许多X
,我用 写入日志\typeout
。
代码:
\documentclass{article}
\RequirePackage{etoolbox}
\RequirePackage{pgfplotstable}
\RequirePackage{pgfplots}
\usepackage{booktabs}
\begin{filecontents*}{test.csv}
ColA, ColB, ColC
0.17, 0.91, 0.67
0.15, 0.17, 0.92
0.48, 0.1, 0.28
\end{filecontents*}
% better and easier definition of \buildTable
\def\buildTableA#1{%
\pgfplotstableread[col sep = comma]{#1}\rawdata%
\pgfplotstabletypeset[after row=\midrule]{\rawdata}%
}%
% unnecessarily complicated and dangerous definition, using \appto instead of \xappto
\def\buildTableB#1{%
\def\temp{after row=\noexpand\midrule}%
\def\codeforpgf{}%
\typeout{XXXXXXXXXXXXXXXXXXXX \string\buildTableB}%
\show\temp
\show\codeforpgf
\appto\codeforpgf{\temp}%
\show\codeforpgf
\pgfplotstableread[col sep = comma]{#1}\rawdata%
\xdef\theTable{\noexpand\pgfplotstabletypeset[\codeforpgf]}%
\show\theTable
\theTable{\rawdata}%
}%
% unnecessarily complicated and dangerous definition
\def\buildTableC#1{%
\def\temp{after row=\noexpand\noexpand\noexpand\midrule}%
\def\codeforpgf{}%
\typeout{XXXXXXXXXXXXXXXXXXXX \string\buildTableC}%
\show\temp
\show\codeforpgf
\xappto\codeforpgf{\temp}%
\show\codeforpgf
\pgfplotstableread[col sep = comma]{#1}\rawdata%
\xdef\theTable{\noexpand\pgfplotstabletypeset[\codeforpgf]}%
\show\theTable
\theTable{\rawdata}%
}%
\begin{document}
\begin{table}
\buildTableA{test.csv}
\buildTableB{test.csv}
\buildTableC{test.csv}
\end{table}
\end{document}