答案1
这扩展了我在 OP 链接的答案中给出的先前解决方案
基本上,我再次采用与按部分存储人物外表相同的策略,通过收集带有标签的人物出现的部分编号,然后再次提取此列表并设置一个由\ListOfPersons
长表组成的表格,其中包含指向相关部分的超链接。
我认为,代码可以浓缩一点,但是如下所示:
\documentclass{scrartcl}
\usepackage{array}
\usepackage{longtable}
\usepackage{xcolor}
\usepackage{refcount}
\usepackage{xparse}
\usepackage{hyperref}
\newcolumntype{L}[1]{>{\raggedright}p{#1}}
\newcolumntype{R}[1]{>{\raggedleft}p{#1}}
\newif\ifusehyperlinks
\ExplSyntaxOn
\seq_new:N \g_luke_listofpersons_seq
\seq_new:N \l_luke_listofpersons_seq
\NewDocumentCommand{\addperson}{m}{%
\seq_if_in:NnF \g_luke_listofpersons_seq {#1} {
\seq_gput_right:Nn \g_luke_listofpersons_seq {#1}
\seq_gremove_duplicates:N \g_luke_listofpersons_seq
\seq_new:c {g_luke_#1_scene_seq }
}
\int_compare:nNnT {\number\value{section}} > {0} {
\seq_gput_right:cx {g_luke_#1_scene_seq } {\thesection}
}
}
\NewDocumentCommand{\addpersonlocal}{m}{%
\seq_gput_right:Nn \l_luke_listofpersons_seq {#1}
\int_compare:nNnT {\number\value{section}} > {0} {
\seq_gput_right:cx {g_luke_#1_scene_seq } {\thesection}
}
% \seq_show:c {g_luke_#1_scene_seq }
}
\cs_new:Npn \IfPersonCalledAlreadyF #1#2 {%
\seq_if_in:NnF \l_luke_listofpersons_seq {#1} {#2}
}
\NewDocumentCommand{\DisplayPersons}{}{%
\seq_clear:N \l_luke_listofpersons_seq
\group_begin:
\seq_clear:N \l_tmpa_seq
\seq_map_inline:Nn \g_luke_listofpersons_seq {%
\IfRefUndefinedExpandable{##1\thesection}{}{
\seq_put_right:Nn \l_tmpa_seq {\use:c{##1h}}
}
}
\seq_if_empty:NF \l_tmpa_seq {
\PrePersonList
\seq_use:Nn \l_tmpa_seq {,~}
\PostPersonList
}
\group_end:
}
\cs_generate_variant:Nn \seq_set_from_clist:Nn {Nx}
% This creates the table entry line per person, by 'cracking' the stored list of sections into the relevant section number and then provides a hyper link
\cs_new:Npn \generatelistofpersonstableline {
\seq_map_inline:Nn \g_luke_listofpersons_seq {
\seq_set_from_clist:Nx \l_tmpa_seq {\getrefnumber{person::##1}}
\seq_if_empty:NF \l_tmpa_seq {
\use:c{##1h} & \seq_set_from_clist:Nx \l_tmpa_seq {\getrefnumber{person::##1}}
\int_set:Nn \l_tmpa_int {\seq_count:N \l_tmpa_seq}
\int_zero:N \l_tmpb_int
\seq_map_inline:Nn \l_tmpa_seq {
\int_incr:N \l_tmpb_int
\ifusehyperlinks
\hyperlink{section.####1}{####1}
\else
####1
\fi
\int_compare:nNnF {\l_tmpa_int} = {\l_tmpb_int} {
,\space
}
}
\tabularnewline
}
}
}
\NewDocumentCommand{\ListOfPersons}{}{%
\begin{longtable}{L{5cm}R{10cm}}
\bfseries Person & \bfseries Sections \tabularnewline
\endhead
\generatelistofpersonstableline
\end{longtable}
}
\makeatletter
\NewDocumentCommand{\storelistofpersons}{}{%
\seq_map_inline:Nn \g_luke_listofpersons_seq {
\protected@edef\@currentlabel{\seq_use:cn {g_luke_##1_scene_seq}{,}}
\label{person::##1}%
% ##1 \space \seq_use:cn {g_luke_##1_scene_seq} {,}
% \par
}
}
\makeatother
\AtEndDocument{%
\storelistofpersons%
}
\ExplSyntaxOff
\NewDocumentCommand{\PostPersonList}{}{%
\bigskip%
}
\NewDocumentCommand{\displayindividualperson}{m}{%
\textbf{#1}%
}
\NewDocumentCommand{\PrePersonList}{}{%
{\large \bfseries Persons in Section \thesection}
}
\makeatletter
\NewDocumentCommand{\NewPerson}{m+m}{%
% Add this person to the global list
\addperson{#1}%
% Now define the personal \...x command
\expandafter\NewDocumentCommand\csname #1x\endcsname{+m}{%
%Check if the person has been called in the local section already
\IfPersonCalledAlreadyF{#1}{%
\addpersonlocal{#1}
% Add the personal to the local list, i.e. per section
% Check whether the label has been defined already
\protected@edef\@currentlabel{\thesection.#1}\label{#1\thesection}
}%
\textsc{#1:} ##1%
}% End of the \...x command
\expandafter\NewDocumentCommand\csname #1h\endcsname{}{%
#2{#1}%
}
}% End of \NewPerson
\makeatother
\NewPerson{tom}{\colorbox{green}}
\NewPerson{frodo}{\colorbox{yellow}}
\NewPerson{Gandalf}{\fcolorbox{yellow}{yellow!60!blue}}
\NewPerson{Paulo}{\colorbox{green}}
\NewPerson{David}{\colorbox{orange}}
\usehyperlinkstrue
\begin{document}
\ListOfPersons
\section{In the supermarket}
\DisplayPersons
\tomx{Hi, I'm Tom!}
\frodox{Hi, I'm Frodo!}
\section{At TeX.SE}
\DisplayPersons
\frodox{Hi, I'm Frodo!}
\frodox{I am going to Mordor}
\Gandalfx{Cast the ring into the fire!}
\tomx{Waiting for Godot}
\section{In TeX.SE Chat}
\DisplayPersons
\Paulox{Quack!}
\Gandalfx{Quack!}
\Davidx{I've got a recipe for Duck in Orange Sauce}
\tomx{That's marvellous}
\frodox{Pineapple pizza!}
\end{document}