第一个解决方案

第一个解决方案

这有点人为,但假设以下内容作为背景:

首先,我想为表格添加标签tab:label,为图形添加标签,等等fig:label。其次,我想创建一些命令来包含图形、表格等。

%{caption; label} %table def %table content
\NewDocumentCommand{\includetable}{> { \SplitArgument { 1 } { ; } } m m m}{
  \begin{table}[htb!]
    \captionlabel#1 % the Question is about this line; how do I pass the prefix?
    \begin{tabular}{#2}
        #3
    \end{tabular}
  \end{table}
}

我有一个插入标题和标签的命令,如下所示:

%caption %label prefix %label
\NewDocumentCommand{\captionlabel}{m O{} m}{
    \caption{#1}\label{#2#3} 
}

问题是是否有可能以某种方式调用\captionlabel\includetable传递tab:前缀(类似于\captionlabel {#1.1}[tab:]{#1.2})。

我知道我可以删除 中的可选参数\captionlabel并始终使用\includetable进行调用tab:label,或者我可以将 的参数顺序切换\captionlabel{O{} m m}{m m O{}},或者内联命令。这基本上只是一个例子。

答案1

\NewDocumentCommand用于定义面向用户的命令,但当expl3您定义用户级命令所基于的代码级 API 时,事情会变得更容易、更清晰。其中一个原因是使用 很容易生成代码级函数的变体\cs_generate_variant:Nn,而使用 定义的命令\NewDocumentCommand不支持这一点。以下是两种解决问题的方法,同时保持\captionlabel命令界面的完整性。

第一个解决方案

该解决方案使用代码级函数\fabian_insert_caption_and_label:nnn,其中通过提供的两个参数\SplitArgument占据相邻位置(即位置 2 和 3):

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\cs_new_protected:Npn \fabian_insert_caption_and_label:nnn #1#2#3
  { \caption {#2} \label {#1#3} }

\NewDocumentCommand { \includetable } { > { \SplitArgument { 1 } { ; } } m m m }
  {
    \begin{table}[htb!]
    \centering
    \fabian_insert_caption_and_label:nnn { tab: } #1

    \begin{tabular}{#2}
      #3
    \end{tabular}
    \end{table}
  }

% Useless here, but maybe you want it for other code of yours.
\NewDocumentCommand { \captionlabel } { m O{} m }
  {
    \fabian_insert_caption_and_label:nnn {#2} {#1} {#3}
  }

\ExplSyntaxOff

\begin{document}
  \includetable{Caption text; the label}{ll}{This & is\\ a & table}

  See table~\ref{tab:the label} on page~\pageref{tab:the label}.
\end{document}

第二种解决方案

此解决方案使用的代码级函数\fabian_insert_caption_and_label:nnn与第一个解决方案中的函数不同:它以与您的 相同的顺序接受参数\captionlabel。为了管理两个“不相邻的参数”,我们在拆分 的第一个参数后手动传递它们\includetable。请注意,您可以(可能应该)创建一个与此 相对应的代码级函数\includetable。这样,​​重用代码就更容易了(我没有这样做是为了不混淆所有问题,但它只是我所说的一个简单的包装器:见下文)。

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\cs_new_protected:Npn \fabian_insert_caption_and_label:nnn #1#2#3
  { \caption {#1} \label {#2#3} }

\cs_generate_variant:Nn \fabian_insert_caption_and_label:nnn { xnx }

\seq_new:N \l_fabian_tmp_seq

\NewDocumentCommand { \includetable } { m m m }
  {
    \seq_set_split:Nnn \l_fabian_tmp_seq { ; } {#1}

    \begin{table}[htb!]
    \centering
    \fabian_insert_caption_and_label:xnx
      { \seq_item:Nn \l_fabian_tmp_seq { 1 } }
      { tab: }
      { \seq_item:Nn \l_fabian_tmp_seq { 2 } }

    \begin{tabular}{#2}
      #3
    \end{tabular}
    \end{table}
  }

\NewDocumentCommand { \captionlabel } { m O{} m }
  {
    \fabian_insert_caption_and_label:nnn {#1} {#2} {#3}
  }

\ExplSyntaxOff

\begin{document}
  \includetable{Caption text; the label}{ll}{This & is\\ a & table}

  See table~\ref{tab:the label} on page~\pageref{tab:the label}.
\end{document}

如果担心速度,我会使用\seq_pop:NNtwice 而不是\seq_item:Nntwice,因为后者每次都会遍历整个序列,而\seq_pop:NN只存储和删除第一个项目,这非常快(结果是\q_no_value没有项目可以弹出)。

建议包装\includetable

当我上面说我建议您添加一个与您的相对应的简单代码级函数时\includetable,我的意思只是这样的:

\cs_new_protected:Npn \fabian_include_table:nnn #1#2#3
  {
    \seq_set_split:Nnn \l_fabian_tmp_seq { ; } {#1}

    \begin{table}[htb!]
    \centering
    \fabian_insert_caption_and_label:xnx
      { \seq_item:Nn \l_fabian_tmp_seq { 1 } }
      { tab: }
      { \seq_item:Nn \l_fabian_tmp_seq { 2 } }

    \begin{tabular}{#2}
      #3
    \end{tabular}
    \end{table}
  }

\NewDocumentCommand { \includetable } { m m m }
  {
    \fabian_include_table:nnn {#1} {#2} {#3}
  }

这样,您可以非常轻松地定义\fabian_include_table:nnn使用的变体\cs_generate_variant:Nn。您还可以根据需要更改其接口(假设它不是公共包的一部分),而无需更改用户级命令的接口\includetable

两个示例的输出

截屏

答案2

我不推荐这种语法。仅出于学术兴趣,您可以这样做:

\documentclass{article}
\usepackage{xparse}

\NewDocumentCommand{\includetable}{> { \SplitArgument { 2 } { ; } } m m m}{%
  \begin{table}[htb!]
    \centering
    \addcaptionlabel#1
    \begin{tabular}{#2}
        #3
    \end{tabular}
  \end{table}
}
\NewDocumentCommand{\captionlabel}{m O{} m}{%
  \caption{#1}\label{#2#3} 
}
\NewDocumentCommand{\addcaptionlabel}{mmm}{%
  \IfNoValueTF{#3}{%
    \captionlabel{#1}{#2}%
  }{%
    \captionlabel{#1}[#2]{#3}%
  }%
}

\begin{document}

\ref{DEF} and \ref{prefixDEF}

\includetable{ABC;DEF}{cc}{11 & 22 \\ 333 & 4}

\includetable{ABC;prefix;DEF}{cc}{11 & 22 \\ 333 & 4}

\end{document}

在此处输入图片描述

相关内容