使用 def、xdef、let 等从表中读取(和编辑)数据(通过使用 pgf-loop 和 pgfplotstable)

使用 def、xdef、let 等从表中读取(和编辑)数据(通过使用 pgf-loop 和 pgfplotstable)

如果我从一张桌子上读\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}

相关内容