对于刚开始学习 Tex 的人来说,如何分解和解释这个复杂的命令呢?

对于刚开始学习 Tex 的人来说,如何分解和解释这个复杂的命令呢?

我得到了这个 Tex 命令,作为解决另一个问题并且它确实有效。但我很难理解它的工作原理,因为我对 Latex 编码不是很熟练,而且我想学习。

%\DTLfetchifnull{<db name>}%
%               {<column1 name>}%
%               {<column1 value>}%
%               {<column2 name>}%
%               {<tokens in case <column2-value> is not a null-value>}%
%               {<tokens in case <column2-value> is a null-value>}%
%               {<tokens in case <column1-value> does not exist>}%
%
% Both with <tokens in case <column2-value> is not a null-value> and with
% <tokens in case <column2-value> is a null-value> the macro
% \dtlcurrentvalue is defined to yield the value of the column whose name
% is <column2 name>.
%
\makeatletter
\@ifundefined{NewDocumentCommand}%
{\newcommand\DTLfetchifnull[7]}%
{\NewDocumentCommand\DTLfetchifnull{mmmmmmm}}%
{%
  \begingroup%
    \protected@edef\@dtl@dogetrowforvalue{%
        \noexpand%
  \endgroup
  \noexpand\dtlgetrowindex{\noexpand\dtl@rowidx}{#1}{\dtlcolumnindex{#1}{#2}}{#3}%
  }\@dtl@dogetrowforvalue%
  \ifx \dtl@rowidx\dtlnovalue%
    \expandafter\@secondoftwo%
  \else%
    \expandafter\@firstoftwo%
  \fi%
  {%
    \edtlgetrowforvalue{#1}{\dtlcolumnindex{#1}{#2}}{#3}%
    \dtlgetentryfromcurrentrow{\dtlcurrentvalue}{\dtlcolumnindex{#1}{#4}}%
    \DTLifnull{\dtlcurrentvalue}{#6}{#5}% 
  }{%
    #7%
  }%
}%
\makeatother
  • 据我所知,\makeatletter ... \makeatother 是必要的,因为我们改变了 NewDocumentCommand 和 newcommand 的一些基本内容?
  • @ifundefined{NewDocumentCommand}% 据我所知,是否可以在没有 \usepackage{xparse} 的情况下使用 NewDocumentCommand 而不是 newcommand?

我们为什么需要这个?我们可以只使用 \usepackage{xparse} 并跳过整个步骤吗:

\makeatletter
\@ifundefined{NewDocumentCommand}%
{\newcommand\DTLfetchifnull[7]}%
...
\makeatother

或者这样做有什么好处吗?

  • \begingroup ... \endgroup 据我所知,它类似于 '{ }',但行为不同

  • 但是它包围了“\protected@edef@dtl@dogetrowforvalue{”,所以“}”在外面,这是怎么回事?

    \begingroup% \protected@edef@dtl@dogetrowforvalue{% \noexpand% \endgroup \noexpand\dtlgetrowindex{\noexpand\dtl@rowidx}{#1}{\dtlcolumnindex{#1}{#2}}{#3}% }@dtl@dogetrowforvalue%

我发现很难读懂这些函数是如何封装的,也很难决定哪个是哪个函数的参数或者只是跟在函数后面。

这表示检查 if(\dtl@rowidx\dtlnovalue) do \expandafter@secondoftwo else \expandafter@firstoftwo。

  \ifx \dtl@rowidx\dtlnovalue
    \expandafter\@secondoftwo
  \else
    \expandafter\@firstoftwo
  \fi

@firstoftwo 和 @secondoftwo 是紧随其后的花括号内的两个选项吗?

答案1

\makeatletter并且\makeatother是必需的,以便允许@在其中使用命令名称。这没什么特别的。

第一个想法是,如果可用就使用它,否则就使用\NewDocumentCommand{\DTLfetchifnull}{mmmmmmm}标准(为了与旧文档兼容)。\newcommand{\DTLfetchifnull}[7]

随着新版本的发布,我们基本上得到了

\NewDocumentCommand\DTLfetchifnull{mmmmmmm}
{%
  \begingroup%
    \protected@edef\@dtl@dogetrowforvalue{%
        \noexpand%
  \endgroup
  \noexpand\dtlgetrowindex{\noexpand\dtl@rowidx}{#1}{\dtlcolumnindex{#1}{#2}}{#3}%
  }\@dtl@dogetrowforvalue%
  \ifx \dtl@rowidx\dtlnovalue%
    \expandafter\@secondoftwo%
  \else%
    \expandafter\@firstoftwo%
  \fi%
  {%
    \edtlgetrowforvalue{#1}{\dtlcolumnindex{#1}{#2}}{#3}%
    \dtlgetentryfromcurrentrow{\dtlcurrentvalue}{\dtlcolumnindex{#1}{#4}}%
    \DTLifnull{\dtlcurrentvalue}{#6}{#5}% 
  }{%
    #7%
  }%
}%

这表明编程风格不太好。例如,有几个无用的%,但它们没有危害,只是令人讨厌。而且第一个\noexpand是无用的,因为`\endgroup 不可扩展。我会把它写成

\NewDocumentCommand\DTLfetchifnull{mmmmmmm}
{%
  \begingroup
    \protected@edef\@dtl@dogetrowforvalue{%
  \endgroup
  \noexpand\dtlgetrowindex{\noexpand\dtl@rowidx}{#1}{\dtlcolumnindex{#1}{#2}}{#3}%
  }\@dtl@dogetrowforvalue
  \ifx \dtl@rowidx\dtlnovalue
    \expandafter\@secondoftwo
  \else
    \expandafter\@firstoftwo
  \fi
  {%
    \edtlgetrowforvalue{#1}{\dtlcolumnindex{#1}{#2}}{#3}%
    \dtlgetentryfromcurrentrow{\dtlcurrentvalue}{\dtlcolumnindex{#1}{#4}}%
    \DTLifnull{\dtlcurrentvalue}{#6}{#5}% 
  }{%
    #7%
  }%
}

如果是旧版 LaTeX 则第一行应该是\newcommand{\DTLfetchifnull}[7]

这个想法是定义\@dtl@dogetrowforvalue产生

\endgroup
\dtlgetrowindex{\dtl@rowidx}
  {expansion of #1}
  {expansion of \dtlcolumnindex{#1}{#2}}
  {expansion of #3}

然后\@dtl@dogetrowforvalue将执行临时宏,它将为 赋予一个含义\dtl@rowidx\dtlnovalue(取决于参数#1#2#3。初始\endgroup将平衡已经消化的\begingroup,并且的定义\@dtl@dogetrowforvalue将在执行后立即被遗忘\endgroup(但的扩展\@dtl@dogetrowforvalue已经放置在输入流中,因此取消定义它没有问题)。

接下来将 token 与 进行比较\dtlnovalue。构造

\if<something>
  \expandafter\@secondoftwo
\else
  \expandafter\@firstoftwo
\fi
{tokens A}
{tokens B}

在 LaTeX 编程中非常常见。如果测试返回 true,tokens B则使用 ,否则使用tokens A

因此,如果\dtl@rowidx结果是\dtlnovalue,则将使用该参数#7。否则它将是某个合法的行索引和

\edtlgetrowforvalue{#1}{\dtlcolumnindex{#1}{#2}}{#3}%
\dtlgetentryfromcurrentrow{\dtlcurrentvalue}{\dtlcolumnindex{#1}{#4}}%
\DTLifnull{\dtlcurrentvalue}{#6}{#5}% 

将会被使用。找出什么确实需要学习的手册datatool

相关内容