Первое решение

Первое решение

Это немного искусственно, но предположим следующее в качестве контекста:

Во-первых, я хочу добавить метки для таблиц как 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}

введите описание изображения здесь

Связанный контент