如果我从一张桌子上读\def
出
\pgfplotstablegetelem{\row}{No}\of{\mytable}
\def\No{\pgfplotsretval}
就会出错。通过使用\xdef
\pgfplotstablegetelem{\row}{No}\of{\mytable}
\xdef\No{\pgfplotsretval}
它就变得正确了。
但我不得不听在一些评论中 \xdef
不好,更好\let
等等;那么正确的方法是什么?
\begin{filecontents}[overwrite]{originaltable.csv}
No; Name
3; aaa
5; bbb
7; ccc
\end{filecontents}
\documentclass{article}
\usepackage{pgfplotstable}
\pgfplotsset{compat=newest}
\pgfplotstableread[col sep=semicolon, header=true]{originaltable.csv} {\mytable}
\begin{document}
\section{def-variant -- wrong}
\foreach[count=\n from 0] \row in {0,1,2}{%%
% In:
\pgfplotstablegetelem{\row}{No}\of{\mytable}%
\def\No{\pgfplotsretval}%
\pgfplotstablegetelem{\row}{Name}\of{\mytable}%
\def\Name{\pgfplotsretval}%
% Out:
\noindent \No, \Name \\
}%%
\section{xdef-variant -- correct}
\foreach[count=\n from 0] \row in {0,1,2}{%%
% In:
\pgfplotstablegetelem{\row}{No}\of{\mytable}%
\xdef\No{\pgfplotsretval}%
\pgfplotstablegetelem{\row}{Name}\of{\mytable}%
\xdef\Name{\pgfplotsretval}%
% Out:
\noindent \No, \Name \\
}%%
\end{document}
答案1
这实际上与您想要做的任何事情都没有关系pgfplotstable
,在我看来,这更像是一个普遍理解的问题。
\def
/起什么\gdef
作用?
\def
设置一个宏来扩展您提供的定义,而不以任何方式改变它,所以如果您的\def
宏包含其他宏,并且那些其他宏在将来的某个时间发生变化,那么您的宏的结果也会改变。(\gdef
只是的全局变体\def
)
做什么\let
?
\let
让宏具有以下标记的含义。如果以下标记本身就是宏,\let
则将第一个宏设置为具有与其他宏当前相同的含义。
的语法\let
有些复杂。如果您使用的\let\macro<tok>
和<tok>
既不是空格也不是等号,\macro
则其含义为<tok>
(可以是任何字符,具有任何类别代码,或宏或基元)。但您也可以=
在\macro
和之间使用可选的<tok>
,在这种情况下,TeX 将仅忽略后面的一个空格。
\edef
/起什么\xdef
作用?
\edef
效果\def
与但它将完全扩展宏的定义并将扩展的结果分配给宏。(\xdef
只是的全局变体\edef
)
所有内容都在示例文件中
(为简单起见,这里使用了普通的 TeX 语法,在 LaTeX 中也可以同样操作)
本例将通过一个简单易懂的例子展示\def
、\let
和的不同效果。\edef
% helper functions
\def\exponce#1{\unexpanded\expandafter{#1}}
\def\exptwice#1{\expandafter\exponce\expandafter{#1}}
\def\expthrice#1{\expandafter\exptwice\expandafter{#1}}
\newlinechar`\^^J
\def\showfoursteps#1%
{%
\message
{%
^^J%
\unexpanded{#1}-> \exponce{#1}-> \exptwice{#1}-> \expthrice{#1}
^^J%
}%
}
\def\BB{\CC}
\def\CC{CC}
\def\Adef{\BB}
\let\Alet\BB
\edef\Aedef{\BB}
\showfoursteps\Adef
\showfoursteps\Alet
\showfoursteps\Aedef
\def\BB{CC}
\showfoursteps\Adef
\showfoursteps\Alet
\showfoursteps\Aedef
\bye
这将在终端上打印以下内容:
\Adef -> \BB -> \CC -> CC
\Alet -> \CC -> CC-> CC
\Aedef -> CC-> CC-> CC
\Adef -> \BB -> CC-> CC
\Alet -> \CC -> CC-> CC
\Aedef -> CC-> CC-> CC
需要注意什么?
总体来说\def
,它们\let
相当安全。但\edef
如果用在无法安全完全膨胀的材料上,可能会出现严重问题。
用什么来存储其他结果
如果其他例程的结果存储在宏中,而您想将这些结果保存在另一个宏中,\let
那么这就是可行的方法。如果您需要将值保留的时间比当前组更长,则可以添加\let
前缀\global
:\global\let\foo\bar
如果结果由完全扩展返回,\edef
则是可行的方法(对于许多在末尾expl3
使用来产生一些结果而不进一步扩展它们的函数来说,情况都是如此,例如,您可以使用作为一个可扩展的宏来从 的两端删除空格)。\unexpanded
\edef\mymacro{\stripspaces{<stuff>}}
\stripspaces
<stuff>
如果您确切知道某件事需要多少个扩展步骤(例如,\pgfplotsretval
只需要一个步骤),则可以使用\unexpanded
原语和\expandafter
来触发所需的精确扩展步骤数,即使在内部也是如此\edef
。因此,您也可以使用以下内容:
\def\BB{\CC}
\edef\AA{BB is \unexpanded\expandafter{\BB}}
适用于您的情况:
您可以使用\let
来分配\No
当前的含义,\pgfplotsretval
如下所示:
\begin{filecontents}[overwrite]{originaltable.csv}
No; Name
3; aaa
5; bbb
7; ccc
\end{filecontents}
\documentclass{article}
\usepackage{pgfplotstable}
\pgfplotsset{compat=newest}
\pgfplotstableread[col sep=semicolon, header=true]{originaltable.csv} {\mytable}
\begin{document}
\section{let-variant -- correct}
\foreach[count=\n from 0] \row in {0,1,2}{%%
% In:
\pgfplotstablegetelem{\row}{No}\of{\mytable}%
\let\No\pgfplotsretval%
\pgfplotstablegetelem{\row}{Name}\of{\mytable}%
\let\Name\pgfplotsretval%
% Out:
\noindent \No, \Name \\
}%%
\end{document}