这有点人为,但假设以下内容作为背景:
首先,我想为表格添加标签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:NN
twice 而不是\seq_item:Nn
twice,因为后者每次都会遍历整个序列,而\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}