给定一些文本,我想将各个段落标记为属于一个或多个类别,并生成这些段落的反向列表,按其标签逐项列出(请参见下文,并参见第二版的注释,其中添加了命名tagging
环境,允许多个索引)。
理想情况下,诸如这样的命令\tag[tag1,tag2,...]{this is the text}
将用于将文本的一部分与一个或多个标签关联起来。
举例来说,让塞万提斯的《堂吉诃德》(1605)的第一段标记如下(内容无关紧要)。
\resettags[我的标签]
在 \tag[place]{la Mancha} 的路上,我听不到任何声音,也没有时间再见到一头 \tag[weapon]{lanza} 野兽、\tag[weapon]{adarga} antigua、\tag[animal]{rocín} flaco 和 \tag[animal]{galgo corredor} 。一个 \tag[food]{olla} 的 \tag[food,animal]{vaca} , \tag[food,animal]{carnero}, \tag[food]{salpicón} 的 \tag[food]{duelos y quebrantos} 的 \tag[day]{sábados}, \tag[food]{lantejas} 的 \tag[day]{viernes}, 一些 \tag[food,animal]{palomino} 的 \tag[day]{domingos} 的 ,消耗了庄园的三部分。
\maketags[我的标签]
该\maketags[<tag index>]
命令将计算并插入反向标签索引。根据上述内容,我将获得:
标签索引
动物:卡内罗;加利哥犬;帕洛米诺马;詐辛;休假。
天: 多明戈斯;星期六;维尔讷。
食物:双子座和长颈鹿;兰特哈斯;奥拉;帕洛米诺马;萨尔皮孔;休假;卡内罗。
地方:拉曼恰。
武器: 阿达加; 兰扎。
注意:标签和每个标签下的条目按字母顺序排列,分隔符为“;”。这些可能是默认选项,要更改其中一个,可以执行以下操作\maketags[name=mytags,sort=false,sep=|]
更新:设计略微发展/融合到下面显示的用法:
\usepackage[tagsmult] % loads .sty
\begin{document}
...
\begin{tagging}[txt1]
... \tag{tag1}{text snippet} ...
... \tag{tag1,tag2}{text snippet} ...
... \tag{tag3}{text snippet} ...
\end{tagging}
...
\begin{tagging}[txt2]
... tagged text 2
\end{tagging}
...
\begin{tagging}[txt1] % note reuse of 'txt1'
... tagged text 3
\end{tagging}
...
\section*{Txt1 Index}
\maketags[txt1] % combines two 'txt1' blocks
\section*{Txt2 Index}
\maketags[txt2]
\end{document}
答案1
这是使用 LaTeX3 和 expl3 的答案。我已将部分语法更改为更符合 LaTeX 标准的语法,但可以很容易地改回来。另请注意,这与amsmath
标签冲突,因此如果您想同时使用两者,您可能需要更改名称。
\ExplSyntaxOn
% Create a new command with no arguments that creates and clears the tag index
\NewDocumentCommand{\resettags}{}{%
\prop_gclear_new:N \tag_index_prop
}
% Create a new command with two (m)andatory arguments, the tag(s) and the text
\NewDocumentCommand{\tag}{mm}{%
% Preserve the text
#2
% Split the tags up into a temporary sequence
\seq_set_split:Nnn \l_tmpa_seq {,} {#1}
% Loop through the tags
\seq_map_inline:Nn \l_tmpa_seq {%
% Check if the tag has been created yet
\prop_get:NnNTF \tag_index_prop {##1} \l_tmpa_tl {%
% If already created
% Add the text to the tag index as a comma separated value
\prop_put:Nnx \tag_index_prop {##1} { \exp_not:V \l_tmpa_tl,#2 }
} {%
% If not yet created
% Set the tag's value in the index to the text
\prop_put:Nnn \tag_index_prop {##1} { #2 }
}
}
}
% Create a new command with one (o)ptional argument, the options for the command
\NewDocumentCommand{\maketags}{O{}}{%
% Define options for make tags
\keys_define:nn {make_tags_module}
{
sort .bool_set:N = \tag_sort_keys_bool,
sort .initial:n = true,
sep .tl_set:N = \tag_word_sep_tl,
sep .initial:n = ;\ ,
}
% Read in options
\keys_set:nn {make_tags_module} { #1 }
% Turn the keys of the tag index into a seq for sorting
\seq_clear:N \l_tmpa_seq
\prop_map_inline:Nn \tag_index_prop {%
\seq_put_right:Nn \l_tmpa_seq {##1}
}
% Check if should sort
\bool_if:NTF \tag_sort_keys_bool {%
% Sort the tags in alphabetical order
\seq_sort:Nn \l_tmpa_seq {%
% You can use \str_compare:nNnTF here, but it wasn't in my distribution
\int_compare:nTF {\pdfstrcmp{##1}{##2} < 0}
{ \sort_return_same: }
{ \sort_return_swapped: }
}
} {}
% Print each tag
\seq_map_inline:Nn \l_tmpa_seq {%
% Get the words
\prop_get:NnN \tag_index_prop {##1} \l_tmpa_tl
% Split the words by comma
\seq_set_split:NnV \l_tmpb_seq {,} \l_tmpa_tl
% Check if should sort
\bool_if:NTF \tag_sort_keys_bool {%
% Sort the words in alphabetical order
\seq_sort:Nn \l_tmpb_seq {%
\int_compare:nTF {\pdfstrcmp{####1}{####2} < 0}
{ \sort_return_same: }
{ \sort_return_swapped: }
}
} {}
% Print
\noindent\textbf{##1}:\ \seq_use:Nn \l_tmpb_seq {\tag_word_sep_tl} \par
}
}
\ExplSyntaxOff
它的使用方式如下:
\begin{document}
\resettags
En un lugar de \tag{place}{la Mancha}, de cuyo nombre no quiero acordarme, no ha mucho tiempo que vivía un hidalgo de los de \tag{weapon}{lanza} en astillero, \tag{weapon}{adarga} antigua, \tag{animal}{rocín} flaco y \tag{animal}{galgo} corredor. Una \tag{food}{olla} de algo más \tag{food,animal}{vaca} que \tag{food,animal}{carnero}, \tag{food}{salpicón} las más noches, \tag{food}{duelos y quebrantos} los \tag{day}{sábados}, \tag{food}{lantejas} los \tag{day}{viernes}, algún \tag{food,animal}{palomino} de añadidura los \tag{day}{domingos}, consumían las tres partes de su hacienda.
\maketags
% or
\maketags[sep={,}\ ]
% or
\maketags[sort=false, sep=-]
\end{document}
渲染效果与问题中展示的差不多。希望这对你有帮助!
编辑:添加了对命名索引的支持,并将其纳入环境,如评论中所述。编辑 2:修复命名并进行标签合并。
\ExplSyntaxOn
% Create a new command with no arguments that creates and clears the tag index
\NewDocumentEnvironment{tagged}{o}{%
\prop_gclear_new:N \g__tag_index_prop
}{%
\IfNoValueTF{#1}{}{%
\prop_if_exist:cTF {g__tag_index_#1_prop} {
% If it already exists, merge
\prop_map_inline:Nn \g__tag_index_prop {
\prop_get:cnNTF {g__tag_index_#1_prop} { ##1 } \l_tmpa_tl {
% Merge
\prop_gput:cno {g__tag_index_#1_prop} { \l_tmpa_tl, ##2 }
} {
% Add
\prop_gput:cnn {g__tag_index_#1_prop} { ##1 } { ##2 }
}
}
} {
% If it doesn't exist, just copy everything over
\prop_new:c {g__tag_index_#1_prop}
\prop_gset_eq:cN {g__tag_index_#1_prop} \g__tag_index_prop
}
}
}
% Create a new command with two (m)andatory arguments, the tag(s) and the text
\NewDocumentCommand{\tag}{mm}{%
% Preserve the text
#2
% Split the tags up into a temporary sequence
\seq_set_split:Nnn \l_tmpa_seq {,} {#1}
% Loop through the tags
\seq_map_inline:Nn \l_tmpa_seq {%
% Check if the tag has been created yet
\prop_get:NnNTF \g__tag_index_prop {##1} \l_tmpa_tl {%
% If already created
% Add the text to the tag index as a comma separated value
\prop_gput:Nno \g__tag_index_prop {##1} { \l_tmpa_tl, #2 }
} {%
% If not yet created
% Set the tag's value in the index to the text
\prop_gput:Nnn \g__tag_index_prop {##1} { #2 }
}
}
}
% Create a new command with one (o)ptional argument, the options for the command
\NewDocumentCommand{\maketags}{O{}}{%
% Define options for make tags
\keys_define:nn {make_tags_module}
{
name .tl_set:N = \tag_name_tl,
name .initial:n =,
sort .bool_set:N = \tag_sort_bool,
sort .initial:n = true,
sep .tl_set:N = \tag_word_sep_tl,
sep .initial:n = ;\ ,
}
% Read in options
\keys_set:nn {make_tags_module} { #1 }
\tl_if_empty:NTF \tag_name_tl {
\prop_set_eq:NN \l_tmpa_prop \g__tag_index_prop
} {
\prop_set_eq:Nc \l_tmpa_prop {g__tag_index_ \tag_name_tl _prop}
}
% Turn the keys of the tag index into a seq for sorting
\seq_clear:N \l_tmpa_seq
\prop_map_inline:Nn \l_tmpa_prop {%
\seq_put_right:Nn \l_tmpa_seq {##1}
}
% Check if should sort
\bool_if:NTF \tag_sort_bool {%
% Sort the tags in alphabetical order
\seq_sort:Nn \l_tmpa_seq {%
% You can use \str_compare:nNnTF here, but it wasn't in my distribution
\int_compare:nTF {\pdfstrcmp{##1}{##2} < 0}
{ \sort_return_same: }
{ \sort_return_swapped: }
}
} {}
% Print each tag
\seq_map_inline:Nn \l_tmpa_seq {%
% Get the words
\prop_get:NnN \l_tmpa_prop {##1} \l_tmpa_tl
% Split the words by comma
\seq_set_split:NnV \l_tmpb_seq {,} \l_tmpa_tl
% Check if should sort
\bool_if:NTF \tag_sort_bool {%
% Sort the words in alphabetical order
\seq_sort:Nn \l_tmpb_seq {%
\int_compare:nTF {\pdfstrcmp{####1}{####2} < 0}
{ \sort_return_same: }
{ \sort_return_swapped: }
}
} {}
% Print
\noindent\textbf{##1}:\ \seq_use:Nn \l_tmpb_seq {\tag_word_sep_tl} \par
}
}
\ExplSyntaxOff
\begin{document}
\begin{tagged}[sec1]
En un lugar de \tag{place}{la Mancha}, de cuyo nombre no quiero acordarme, no ha mucho tiempo que vivía un hidalgo de los de \tag{weapon}{lanza} en astillero, \tag{weapon}{adarga} antigua, \tag{animal}{rocín} flaco y \tag{animal}{galgo} corredor. Una \tag{food}{olla} de algo más \tag{food,animal}{vaca} que \tag{food,animal}{carnero}, \tag{food}{salpicón} las más noches, \tag{food}{duelos y quebrantos} los \tag{day}{sábados}, \tag{food}{lantejas} los \tag{day}{viernes}, algún \tag{food,animal}{palomino} de añadidura los \tag{day}{domingos}, consumían las tres partes de su hacienda.
\end{tagged}
\begin{tagged}[sec2]
\tag{test}{Lorem} ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis \tag{test2}{aute} irure dolor in reprehenderit in voluptate velit esse cillum dolore eu \tag{test}{fugiat} nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
\end{tagged}
\begin{tagged}[sec1]
\tag{test}{Lorem} ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis \tag{test2}{aute} irure dolor in reprehenderit in voluptate velit esse cillum dolore eu \tag{test}{fugiat} nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
\end{tagged}
% by default prints the previous if no name is given
\maketags
%or
\maketags[name=sec1]
% or
\maketags[name=sec2]
\end{document}
答案2
在 OpTeX 中,我们可以通过以下宏来解决这个任务:
\def\tags{}
\def\tag[#1]#2{\foreach#1,\do##1,{\unskip
\ifcsname tag:##1\endcsname \ea\addto\csname tag:##1\endcsname{{#2}}%
\else \sdef{tag:##1}{{#2}}\ea\addto\ea\tags\ea{\csname tag:##1\endcsname}%
\fi
}}
\def\sort #1\endsort {\def\slist{}\tmpnum=0
\foreach #1\do
{\ifx.##1\else \incr\tmpnum
\ea\addto\ea\slist\ea{\csname+##1\endcsname}%
\sdef{+##1}{##1}\fi
}
\_dosorting\slist
\ea\foreach \slist \do{\decr\tmpnum ##1\ifnum\tmpnum=0.\else; \fi}%
}
\def\maketags{%
\_dosorting\tags
\ea \xargs \ea \newitem \tags ;
}
\def\newitem #1{\par \noindent \ea\tagname\string#1;
\ea\sort #1.\endsort
}
\def\tagname#1:#2;{{\bf#2}:}
%% test:
En un lugar de \tag[place]{la Mancha}, de cuyo nombre no quiero acordarme, no ha mucho tiempo que vivía un hidalgo de los de \tag[weapon]{lanza} en astillero, \tag[weapon]{adarga} antigua, \tag[animal]{rocín} flaco y \tag[animal]{galgo corredor}. Una \tag[food]{olla} de algo más \tag[food,animal]{vaca} que \tag[food,animal]{carnero}, \tag[food]{salpicón} las más noches, \tag[food]{duelos y quebrantos} los \tag[day]{sábados},
\tag[food]{lantejas} los \tag[day]{viernes}, algún
\tag[food,animal]{palomino} de añadidura los \tag[day]{domingos}, consumían las tres partes de su hacienda.
\bigskip
\maketags
\bye