É um pouco artificial, mas assuma o seguinte como contexto:
Primeiro, quero adicionar rótulos para tabelas como tab:label
, para figuras como fig:label
e assim por diante. Segundo, quero criar alguns comandos para incluir figuras, tabelas, etc.
%{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}
}
E eu tenho um comando que insere uma legenda e um rótulo, que tem a seguinte aparência:
%caption %label prefix %label
\NewDocumentCommand{\captionlabel}{m O{} m}{
\caption{#1}\label{#2#3}
}
A questão é se é de alguma forma possível chamar \captionlabel
e \includetable
passar o tab:
prefixo (algo como \captionlabel {#1.1}[tab:]{#1.2}
).
Eu sei que poderia remover o argumento opcional \captionlabel
e sempre chamar \includetable
with tab:label
, ou poderia mudar a ordem dos argumentos \captionlabel
para {O{} m m}
ou {m m O{}}
, ou incorporar o comando. É basicamente apenas um exemplo.
Responder1
\NewDocumentCommand
serve para definir comandos voltados para o usuário, mas as coisas ficam mais fáceis e limpas quando expl3
você define uma API em nível de código na qual os comandos em nível de usuário são baseados. Uma das razões é que é muito fácil gerar variantes de funções em nível de código com \cs_generate_variant:Nn
, enquanto os comandos definidos com \NewDocumentCommand
não suportam isso. Aqui estão duas maneiras de resolver seu problema que mantêm \captionlabel
intacta a interface do seu comando.
Primeira solução
Esta solução usa uma função em nível de código \fabian_insert_caption_and_label:nnn
onde os dois argumentos fornecidos \SplitArgument
ocupam posições adjacentes (ou seja, posições 2 e 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}
Segunda solução
Esta solução usa uma função em nível de código \fabian_insert_caption_and_label:nnn
diferente daquela da primeira solução: ela aceita os argumentos na mesma ordem que o seu arquivo \captionlabel
. Para gerenciar os dois “argumentos não adjacentes”, passamos-os manualmente após dividirmos o primeiro argumento de \includetable
. Observe que você poderia, e provavelmente deveria, criar uma função em nível de código correspondente a this \includetable
. Dessa forma, reaproveitar o código fica mais fácil (não fiz isso para não misturar todos os problemas, mas é apenas um simples wrapper que estou falando: veja abaixo).
\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}
Se a velocidade for uma preocupação, eu usaria \seq_pop:NN
duas vezes em vez de \seq_item:Nn
duas vezes, porque o último itera toda a sequência todas as vezes, enquanto \seq_pop:NN
apenas armazena e remove o primeiro item, o que é muito rápido (o resultado é \q_no_value
quando não há mais nenhum item para aparecer ).
Invólucro sugerido para\includetable
Quando eu disse acima, sugiro que você adicione uma função simples em nível de código correspondente ao seu \includetable
, o que eu quis dizer foi simplesmente algo assim:
\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}
}
Dessa forma, você pode definir facilmente variantes de \fabian_include_table:nnn
uso de \cs_generate_variant:Nn
. Você também pode alterar sua interface se necessário (supondo que não faça parte de um pacote público) sem alterar a interface do comando em nível de usuário \includetable
.
Saída de ambos os exemplos
Responder2
Não posso recomendar tal sintaxe. Apenas por interesse acadêmico, veja como você pode fazer:
\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}