Особый случай для последнего элемента с \foreach

Особый случай для последнего элемента с \foreach

Я хочу создать функцию, которая генерирует список ссылок на уравнения из списка входных данных, разделенных запятыми. Например:

\erefs{eq:first, eq:second, eq:third}
\erefs{eq:first}

дает следующее:

(\ref{eq:first}), (\ref{eq:second}), and (\ref{eq:third})
(\ref{eq:first})

Я могу правильно позаботиться о списке из 1 элемента, но у меня возникли проблемы с генерацией 'and' для последнего элемента. Есть идеи, как добавить 'and' в этот код?

\documentclass{article}
\usepackage{tikz, amsmath, hyperref}

\def\erefs#1{%
 \gdef\firstelement{1}
 \foreach \e [count=\ni] in {#1}{%
   \ifnum\firstelement=0 , \fi %
   (\ref{\e})%
   \gdef\firstelement{0}%
 }
}

\begin{document}
\begin{equation}\label{eq:first}\end{equation}
\begin{equation}\label{eq:second}\end{equation}
\begin{equation}\label{eq:third}\end{equation}
\erefs{eq:first, eq:second, eq:third}
\erefs{eq:first}
\end{document}

Мне нужно использовать пакеты hyperref и amsmath одновременно

ДОБАВЛЕНИЕ: Я часто использую \package{xr}и \externaldocument{...}для ссылки на техническое приложение и люблю ставить TA.перед этими ссылками. Было бы неплохо, если бы необязательный параметр мог передаваться для префикса

Я хочу создать функцию, которая генерирует список ссылок на уравнения из списка входных данных, разделенных запятыми. Например:

\erefs{eq:first, eq:second, eq:third}
\erefs{eq:first}
\erefs[TA]{eq:first, eq:second, eq:third}
\erefs[TA]{eq:first}

дает следующее:

(\ref{eq:first}), (\ref{eq:second}), and (\ref{eq:third})
(\ref{eq:first})
(TA.\ref{eq:first}), (TA.\ref{eq:second}), and (TA.\ref{eq:third})
(TA.\ref{eq:first})

решение1

Вот способ без cleveref, но для этого нужна последняя версия expl3:

\documentclass{article}
\usepackage{xparse,amsmath}

\ExplSyntaxOn
\NewDocumentCommand{\erefs}{sm}
 {
  \IfBooleanTF{#1}
    { \jlperla_erefs:Nn \ref { #2 } }
    { \jlperla_erefs:Nn \eqref { #2 } }
 }
\seq_new:N \l_jlperla_input_seq
\seq_new:N \l_jlperla_output_seq
\cs_new_protected:Npn \jlperla_erefs:Nn #1 #2
 {
  \seq_set_split:Nnn \l_jlperla_input_seq { , } { #2 }
  \seq_clear:N \l_jlperla_output_seq
  \seq_map_inline:Nn \l_jlperla_input_seq
   {
    \seq_put_right:Nn \l_jlperla_output_seq { #1 { ##1 } }
   }
  \seq_use:Nnnn \l_jlperla_output_seq
   { ~ and ~ }   % between two
   { , ~ }       % between more than two
   { , ~ and ~ } % between last two
 }
\ExplSyntaxOff

\begin{document}
Some text before
\begin{align}
0+0&=0\label{eq:first}\\
0+1&=1\label{eq:second}\\
1+1&=2\label{eq:third}
\end{align}

One: \erefs{eq:first}

Two: \erefs{eq:second, eq:third}

Three: \erefs{eq:first,eq:second,eq:third}

One: \erefs*{eq:first}

Two: \erefs*{eq:second, eq:third}

Three: \erefs*{eq:first,eq:second,eq:third}

\end{document}

*-версия использует \ref, тогда как обычная версия использует \eqref(что лучше подходит для уравнений).

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

Последовательность «входа» устанавливается для меток, цикл добавляет \refили \eqrefвокруг них. Затем \seq_use:Nnnnделает правильно во всех случаях.


Вот модификация для разрешения префикса. Я подключаюсь к \eqref, определяя похожую команду для того, чтобы применялось специальное форматирование.

\documentclass{article}
\usepackage{xparse,amsmath}

\makeatletter
\newcommand{\peqref}[2]{\textup{\tagform@{#1\ref{#2}}}}
\newcommand{\pref}[2]{#1\ref{#2}}
\makeatother

\ExplSyntaxOn
\NewDocumentCommand{\erefs}{ s o m }
 {
  \IfBooleanTF{#1}
    {
     \IfNoValueTF{#2}
      { \jlperla_erefs:Nnn \pref { } { #3 } }
      { \jlperla_erefs:Nnn \pref { #2. } { #3 } }
    }
    {
     \IfNoValueTF{#2}
      { \jlperla_erefs:Nnn \peqref { } { #3 } }
      { \jlperla_erefs:Nnn \peqref { #2. } { #3 } }
    }
 }
\seq_new:N \l_jlperla_input_seq
\seq_new:N \l_jlperla_output_seq
\cs_new_protected:Npn \jlperla_erefs:Nnn #1 #2 #3
 {
  \seq_set_split:Nnn \l_jlperla_input_seq { , } { #3 }
  \seq_clear:N \l_jlperla_output_seq
  \seq_map_inline:Nn \l_jlperla_input_seq
   {
    \seq_put_right:Nn \l_jlperla_output_seq { #1 { #2 } { ##1 } }
   }
  \seq_use:Nnnn \l_jlperla_output_seq
   { ~ and ~ }   % between two
   { , ~ }       % between more than two
   { , ~ and ~ } % between last two
 }
\ExplSyntaxOff

\begin{document}
Some text before
\begin{align}
0+0&=0\label{eq:first}\\
0+1&=1\label{eq:second}\\
1+1&=2\label{eq:third}
\end{align}

No prefix

One: \erefs{eq:first}

Two: \erefs{eq:second, eq:third}

Three: \erefs{eq:first,eq:second,eq:third}

One: \erefs*{eq:first}

Two: \erefs*{eq:second, eq:third}

Three: \erefs*{eq:first,eq:second,eq:third}

\bigskip

With prefix

One: \erefs[TA]{eq:first}

Two: \erefs[TA]{eq:second, eq:third}

Three: \erefs[TA]{eq:first,eq:second,eq:third}

One: \erefs*[TA]{eq:first}

Two: \erefs*[TA]{eq:second, eq:third}

Three: \erefs*[TA]{eq:first,eq:second,eq:third}

\end{document}

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

решение2

На самом деле вам не нужен никакой дополнительный пакет, вы можете просто использовать циклы, уже имеющиеся в LaTeX:

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

\documentclass{article}

\makeatletter
\def\erefs#1{%
\count@\z@
\@for\tmp:=#1\do{\advance\count@\@ne}%
\edef\xtmp{\ifcase\count@\or\or\ and\ \else, and\ \fi}%
\@for\tmp:=#1\do{%
\advance\count@\m@ne
\edef\tmp{%
  \noexpand\ref{\expandafter\zap@space\tmp\@gobble{} \@empty}}%
\tmp
\ifnum\count@>\@ne, %
\else
\ifnum\count@=\@ne\xtmp
\fi\fi}}

\makeatother

\begin{document}

\begin{equation}\label{eq:first}\end{equation}
\begin{equation}\label{eq:second}\end{equation}
\begin{equation}\label{eq:third}\end{equation}


A \erefs{eq:first, eq:second, eq:third}

B \erefs{eq:first, eq:second}

C \erefs{eq:first}

\end{document}

решение3

Вот метод общего использования, который используетetoolbox:

\documentclass{article}

\usepackage{etoolbox}

% set up defaults so we don't get an error
% when we try to redefine these commands
\newcommand*{\elementsep}{}%
\newcommand*{\lastelement}{}%
\newcommand*{\prelastelement}{}%

% define the handler macro:
\newcommand*{\dodisplayelement}[1]{%
  \elementsep
  \lastelement
  \renewcommand{\lastelement}{%
    \renewcommand{\elementsep}{, }%
    \renewcommand{\prelastelement}{ and }%
    #1%
  }}%

% define the new command to process a list of elements:
\newcommand*{\displayelements}[1]{%
  % initialise:
  \renewcommand*{\elementsep}{}%
  \renewcommand*{\lastelement}{}%
  \renewcommand*{\prelastelement}{}%
  % Iterate through list
  \forcsvlist{\dodisplayelement}{#1}%
  % Finish off:
  \prelastelement \lastelement
}

\begin{document}

\displayelements{first,second,third,fourth,fifth}

\end{document}

Каждый элемент отображается, \lastelementпоэтому, если элемент представляет собой метку, вы можете использовать:

% define the handler macro:
\newcommand*{\dodisplayelement}[1]{%
  \elementsep
  \lastelement
  \renewcommand{\lastelement}{%
    \renewcommand{\elementsep}{, }%
    \renewcommand{\prelastelement}{ and }%
    \ref{#1}%
  }}%

решение4

С\xintForНеобязательный параметр может быть любым, он не обязательно должен быть TA.

Если бы потребовался расширяемый способ, это можно было бы сделать с помощью некоторых других утилит изxinttools.

xintforlast

\documentclass{article}
\usepackage{amsmath, hyperref}
\usepackage{xinttools}

\makeatletter
% with optional parameter.
\def\erefs {\@ifnextchar[\@erefsTA\@erefs }

\def\@erefs #1{%
 \xintFor ##1 in {#1}\do 
   {\xintifForFirst{}{, \xintifForLast{and }{}}(\ref{##1})}%
}

\def\@erefsTA [#1]#2{%
 \xintFor ##1 in {#2}\do 
   {\xintifForFirst{}{, \xintifForLast{and }{}}(#1, \ref{##1})}%
}

\makeatother

\begin{document}\thispagestyle{empty}
\begin{equation}E=mc^2\label{eq:first}\end{equation}
\begin{equation}E=h\nu\label{eq:second}\end{equation}
\begin{equation}\zeta(s)=0\label{eq:third}\end{equation}

\erefs{eq:first, eq:second, eq:third}

\erefs{eq:first}

\erefs[TA]{eq:first, eq:second, eq:third}

\erefs[TA]{eq:first}
\end{document}

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