Es klingt ein bisschen künstlich, aber nehmen wir als Kontext Folgendes an:
Erstens möchte ich Beschriftungen für Tabellen hinzufügen tab:label
, für Abbildungen usw. fig:label
Zweitens möchte ich einige Befehle erstellen, um Abbildungen, Tabellen usw. einzuschließen.
%{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}
}
Und ich habe einen Befehl, der eine Überschrift und ein Label einfügt, das wie folgt aussieht:
%caption %label prefix %label
\NewDocumentCommand{\captionlabel}{m O{} m}{
\caption{#1}\label{#2#3}
}
\captionlabel
Die Frage ist, ob es irgendwie möglich ist, von anzurufen \includetable
und das tab:
Präfix zu übergeben (so etwas wie \captionlabel {#1.1}[tab:]{#1.2}
).
Ich weiß, dass ich das optionale Argument in entfernen \captionlabel
und immer \includetable
mit aufrufen könnte tab:label
, oder ich könnte die Reihenfolge der Argumente von \captionlabel
in {O{} m m}
oder ändern {m m O{}}
oder den Befehl inline einfügen. Es ist im Grunde nur ein Beispiel.
Antwort1
\NewDocumentCommand
dient zum Definieren von benutzerorientierten Befehlen, aber es ist einfacher und übersichtlicher, expl3
wenn Sie eine API auf Codeebene definieren, auf der die Befehle auf Benutzerebene basieren. Einer der Gründe ist, dass es sehr einfach ist, Varianten von Funktionen auf Codeebene mit zu generieren \cs_generate_variant:Nn
, während mit definierte Befehle \NewDocumentCommand
dies nicht unterstützen. Hier sind zwei Möglichkeiten, Ihr Problem zu lösen, bei denen die Schnittstelle Ihres Befehls intakt bleibt \captionlabel
.
Erste Lösung
Diese Lösung verwendet eine Funktion auf Codeebene, \fabian_insert_caption_and_label:nnn
bei der die beiden über bereitgestellten Argumente \SplitArgument
benachbarte Positionen einnehmen (nämlich die Positionen 2 und 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}
Zweite Lösung
Diese Lösung verwendet eine andere Funktion auf Codeebene \fabian_insert_caption_and_label:nnn
als die erste Lösung: Sie akzeptiert die Argumente in der gleichen Reihenfolge wie Ihre\captionlabel
. Um die beiden „nicht benachbarten Argumente“ zu verwalten, übergeben wir sie manuell, nachdem wir das erste Argument von selbst aufgeteilt haben \includetable
. Beachten Sie, dass Sie eine entsprechende Codeebenenfunktion erstellen könnten und wahrscheinlich auch sollten \includetable
. Auf diese Weise ist die Wiederverwendung des Codes einfacher (ich habe es nicht getan, um nicht alle Probleme zu vermischen, aber ich spreche nur von einem einfachen Wrapper: siehe unten).
\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}
Wenn Geschwindigkeit ein Problem ist, würde ich verwenden\seq_pop:NN
„twice“ statt \seq_item:Nn
„twice“ verwenden, da letzteres jedes Mal die gesamte Sequenz durchläuft, während \seq_pop:NN
nur das erste Element gespeichert und entfernt wird, was sehr schnell ist (das Ergebnis ist, \q_no_value
wenn kein Element mehr zum Entfernen vorhanden ist).
Empfohlene Verpackung für\includetable
Wenn ich das oben sage, würde ich vorschlagen, dass Sie eine einfache Funktion auf Codeebene hinzufügen, die Ihrer\includetable
, die Ihrem entspricht, meinte ich einfach so etwas wie das:
\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}
}
Auf diese Weise können Sie sehr einfach Varianten definieren von\fabian_include_table:nnn
. \cs_generate_variant:Nn
Sie können bei Bedarf auch die Schnittstelle ändern (vorausgesetzt, es ist nicht Teil eines öffentlichen Pakets), ohne die Schnittstelle des Befehls auf Benutzerebene zu ändern \includetable
.
Ausgabe beider Beispiele
Antwort2
Ich kann eine solche Syntax nicht empfehlen. Nur aus akademischem Interesse können Sie Folgendes tun:
\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}