处理可变数量的 pageref

处理可变数量的 pageref

我正在写一份讨论文档,贡献者可以拥有自己的页面,我想在一般文本中提及这些页面,所以我有这个,似乎可以解决问题

% usage: create printed page space for artist and the short form reference
% \artist{Jo Blow}{JoBl}
\newcommand{\artist}[2]{
\newpage
\subsection{#1}
Lorem ipsum
\newpage 
Et tu quoque! #2\label{artist:#2}
% page reserved for artwork by #1
}

% obtain page numbering for artist image page given shortform reference
% \mention{JoBl}
\newcommand{ \mention}[1] { \emph{[p.\pageref{artist:#1}]}}

但我想扩展 mention{} 以获取可变长度的参数列表

我找到了这个通过逗号分隔的参数进行迭代

这是一个我还没学会走路就跑的例子,但请忍耐一下,我只是一个愚蠢的艺术家,我试过了

%!TEX TS-program = lualatex
%!TEX encoding = UTF-8 Unicode
\documentclass{article}

\newcommand{\artist}[2]{
\newpage
\subsection{#1}
Lorem ipsum
\newpage 
Et tu quoque! #2\label{artist:#2}
% page reserved for artwork by #1
}

% obtain page numbering for artist image page given short form reference
% \mention{HoBu}
\newcommand{ \mention}[1] { \emph{[p.\pageref{artist:#1}]}}

\makeatletter
\newcommand{\lmention}[2][$,$]{%
  \def\nextitem{\def\nextitem{#1}}%
  \@for \el:=#2\do{\nextitem\el}%
}
\makeatother

\begin{document}
\artist{Arty Blow}{Arty}

\artist{Jo Blow}{Jo}


  What I want is the stylised \mention{Arty}
  What would be nice would be an arg count to say p.18 or pp.18,23,24

  A list of mentions is \lmention{Arty,Jo,Fred} tho we havent talked about Fred
   Did I forget \lmention{Bart} who is yet to be referenced
 \artist{Bart Beast}{Bart}
\artist{Fred Geest}{Fred}

\end{document}

长话短说,问题来了?我怎样才能让它逐个参数地执行 \pageref 查找

我尝试

\newcommand{\lmention}[2][$:$]{%
  \def\nextitem{\def\nextitem{#1}}%
  \@for \el:=#2\do{\pageref{artist:#2}\nextitem\el}%
}

但得到

A list of mentions is ??Arty??:Jo??:Fred tho we havent talked about Fred

这超出了我的理解范围

答案1

您可以\lmention使用 TeX 原语和经典 TeX 递归循环来定义。

\def\lmention#1{\lmentionA#1,\end,}
\def\lmentionA#1,#2,{\ifx\end#2 [p.\pageref{artist:#1}]\else
   [pp.\pageref{artist:#1}\afterfi{\lmentionB#2,}\fi
}
\def\lmentionB#1,#2,{,\pageref{artist:#1}%
   \ifx\end#2]\else \afterfi{\lmentionB#2,}\fi
}
\def\afterfi #1#2\fi{\fi#1}

请注意,此宏与单个参数(如)一起使用\mention,即扩展为 [p.page]。在其他情况下,它会扩展为 [pp.list-of-pages]。

答案2

您可以使用expl3它来提供您需要的所有工具。

如您所见,只有一个\mention命令可以区分是否提供了一个或多个引用。

\documentclass{article}

\newcommand{\artist}[2]{%
  \newpage
  \subsection{#1}
  Lorem ipsum
  \newpage 
  Et tu quoque! #2\label{artist:#2}
  % page reserved for artwork by #1
}

\ExplSyntaxOn

\NewDocumentCommand{\mention}{m}
 {
  \aldobranti_mention:n { #1 }
 }

\seq_new:N \l__aldobranti_mention_ref_seq
\tl_new:N \l__aldobranti_mention_first_tl

\cs_new_protected:Nn \aldobranti_mention:nn
 {
  % divide the item at the given delimiter
  \seq_set_from_clist:Nn \l__aldobranti_mention_ref_seq { #1 }
  % detach the last item
  \seq_pop_right:NN \l__aldobranti_mention_ref_seq \l__aldobranti_mention_first_tl
  % now process
  \aldobranti_mention_format:n
   {
    % if the sequence is empty, there was just one item: issue 'p.'; otherwise 'pp.'
    \seq_if_empty:NTF \l__aldobranti_mention_ref_seq { p. } { pp. } \nobreakspace
    % now map the sequence to give 'pageref,<space>'
    \seq_map_inline:Nn \l__aldobranti_mention_ref_seq { \pageref{artist:##1},~ }
    % last item should not have comma and space
    \pageref{artist:\l__aldobranti_mention_first_tl}
   }
 }

\cs_new_protected:Nn \aldobranti_mention_format:n
 {% format the whole block (change as desired)
  \textup{[}
  \hspace*{0.1em}
  \textit{#1}
  \hspace*{0.1em}
  \textup{]}
 }

\ExplSyntaxOff

\begin{document}

\artist{Arty Blow}{Arty}

\artist{Jo Blow}{Jo}


What I want is the stylised \mention{Arty}
What would be nice would be an arg count to say p.18 or pp.18,23,24

A list of mentions is \mention{Arty,Jo,Fred} tho we haven't talked about Fred
Did I forget \mention{Bart} who is yet to be referenced

\artist{Bart Beast}{Bart}
\artist{Fred Geest}{Fred}

\end{document}

在此处输入图片描述

答案3

首先要意识到的是,列表的当前元素不是#2而是\el。参数#2是完整列表。因此你需要\pageref{artist:\el}

第二件事与分隔符的位置有关。通常在构建逗号分隔列表时,您可能倾向于执行以下操作:

for each element {
   print element
   print separator
}

请注意,以上是伪代码,而不是实际的 LaTeX 或 TeX。

但是,这样做会得到一个列表element1,element2,element3,,列表末尾有一个不需要的逗号。因此,另一个问题中的代码使用了一个技巧:它将分隔符每个元素,但确保不打印第一个分隔符。这比确保不打印最后一个分隔符更容易,因为在循环中您不知道最后一个元素是什么。诀窍在于,该命令\nextitem最初定义为不打印任何内容,而是执行定义\def\nextitem{#1}。参数#1是逗号,因此从第二次调用开始,\nextitem打印逗号。因此,您需要与引用问题相同的结构,即,\do{\nextitem\el}但不是只打印,而是\el打印\pageref{artist:\el},因此完整地变成\do{\nextitem\pageref{artist:\el}}

要计算参数数量,您可以先循环列表并为每个元素增加一个计数器,然后测试该计数器的值。如果为 1,则打印p.,否则打印pp.。之后,您再次循环列表以进行实际\pageref调用。

附带说明的是,您不需要$,$分隔符,这仅在原始问题中需要,因为那里使用的分隔符是一个数学命令(\triangleright),它需要带有数学模式$。逗号是常规字符,因此不需要数学模式。

完整代码:

\documentclass{article}

\newcommand{\artist}[2]{
\newpage
\subsection{#1}
Lorem ipsum
\newpage 
Et tu quoque! #2\label{artist:#2}
% page reserved for artwork by #1
}

% obtain page numbering for artist image page given short form reference
% \mention{HoBu}
\newcommand{ \mention}[1] { \emph{[p.\pageref{artist:#1}]}}

\makeatletter
\newcounter{mentionargs}
\newcommand{\lmention}[2][,]{%
  \setcounter{mentionargs}{0}%
  \@for \el:=#2\do{\stepcounter{mentionargs}}%
  \ifnum\value{mentionargs}=1%
  p.%
  \else%
  pp.%
  \fi%
  \def\nextitem{\def\nextitem{#1}}%
  \@for \el:=#2\do{\nextitem\pageref{artist:\el}}%
}
\makeatother

\begin{document}
\artist{Arty Blow}{Arty}

\artist{Jo Blow}{Jo}


  What I want is the stylised \mention{Arty}, \mention{Jo}, \mention{Fred}
  What would be nice would be an arg count to say p.2 or pp.18,23,24

  A list of mentions is \lmention{Arty,Jo,Fred} tho we havent talked about Fred
   Did I forget \lmention{Bart} who is yet to be referenced
 \artist{Bart Beast}{Bart}
\artist{Fred Geest}{Fred}

\end{document}

结果:

在此处输入图片描述

相关内容