我一直在尝试寻找一个包或一种方法,以简单的方式在 TeX/LaTeX 中对名称列表进行排序。我尝试了負責包,并查看了 LaTeX3 中的一些新宏,但都没有取得很大的成功。
我想到使用 MakeIndex 程序进行排序和分类。每个发行版都提供该程序,而且 LaTeX 类非常短,很容易被破解,大约只有 36 行(包括我可以删除的词汇表宏),并且在基本书籍或文章类中还有一些用于样式的定义。
这是一个最简单的例子,按职业(类别)对姓名列表进行排序。
\documentclass[11pt]{article}
\usepackage{makeidx}
\def\addName#1#2{\index{Name!#1}\index{#2!#1}}
\makeindex
\begin{document}
\renewcommand{\indexname}{Famous and Infamous Sorted People}
\addName{Leslie Lamport}{Computer Scientist}
\addName{Donald Knuth}{Computer Scientist}
\addName{Tim Berners Lee}{Computer Scientist}
\addName{Brian Kernighan}{Computer Scientist}
\addName{Noam Chomsky}{Linguist}
\addName{Yiannis Lazarides}{Lifelong Trainee \protect\TeX nician}
\addName{Leonard Euler}{Mathematician}
\addName{Carl Friendrich Gauss}{Mathematician}
\addName{August Ferdinard M\"{o}bius}{Mathematician}
%% Importing the .ind file rather than use \printindex
%% so we do not need to redefine the command
%%
\input{indextest.ind}
\begin{verbatim}
\begin{theindex}
\item Lifelong Trainee \TeX nician
\subitem Yiannis Lazarides, 1
\item Linguist
\subitem Noam Chomsky, 1
\end{theindex}
\end{verbatim}
\end{document}
这是个好主意吗?有没有专门用于字母数字排序的软件包?我知道使用外部脚本可以轻松完成,但我正在寻找 TeX/LaTeX 解决方案。你认为这是一个好方法吗?
答案1
我没有查看 Charles 的代码,因为我想看看实现一个可扩展的通用排序宏有多难。事实证明,以连续传递风格实现起来或多或少是比较简单的。
\documentclass{article}
\usepackage{etoolbox}
\makeatletter
% #1 - comparator
% #2 - token list to sort
\newcommand\sort[2]{%
\ifstrempty{#2}
{}% else
{%
\sort@begin#1{}#2\sort@s\sort@begin
}%
}
% helpers
\def\sort@s{\sort@s}
\def\ifsort@s#1{%
\ifx\sort@s#1%
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
}
% #1 - comparator
% #2 - tokens processed so far
% #3 - smallest token so far
% #4 - rest of the list
\def\sort@begin#1#2#3#4\sort@begin{%
\ifsort@s{#4}
{%
\sortend{#3}%
\sort#1{#2}%
}% else
{%
\sort@go#1{#2}{#3}#4\sort@go
}%
}
% #1 - comparator
% #2 - tokens processed so far
% #3 - smallest token so far
% #4 - token under consideration
% #5 - rest of the list
\def\sort@go#1#2#3#4#5\sort@go{%
#1{#3}{#4}{\sort@output#1{#2}{#5}}%
}
% #1 - comparator
% #2 - tokens processed so far
% #3 - rest of the list
% #4 - smaller of the two tokens
% #5 - larger of the two tokens
\def\sort@output#1#2#3#4#5{%
\ifsort@s{#3}
{%
\sortoutput{#4}%
\sort#1{#2{#5}}%
}% else
{%
\sort@begin#1{#2{#5}}{#4}#3\sort@begin
}%
}
\def\sort@numlt#1#2#3{%
\ifnumcomp{#1}<{#2}
{#3{#1}{#2}}% else
{#3{#2}{#1}}%
}
\def\sort@numgt#1#2#3{%
\ifnumcomp{#1}>{#2}
{#3{#1}{#2}}% else
{#3{#2}{#1}}%
}
\def\sort@alpha#1#2#3{%
\ifnumcomp{\pdfstrcmp{#1}{#2}}<{0}
{#3{#1}{#2}}% else
{#3{#2}{#1}}%
}
\newcommand*\sortnumlt{\sort\sort@numlt}
\newcommand*\sortnumgt{\sort\sort@numgt}
\newcommand*\sortalpha{\sort\sort@alpha}
\makeatother
% Change these to change out the sort outputs.
\newcommand*\sortoutput[1]{#1, }
\newcommand*\sortend[1]{#1.}
\begin{document}
\sortnumgt{87632147{55}9{8/2}}
\sortalpha{{Goodbye}{Cruel}{World}}
\renewcommand*\sortoutput[1]{#1}
\renewcommand*\sortend[1]{#1}
\edef\temp{\sortnumlt{87632147{55}9}}
\texttt{\meaning\temp}
\end{document}
我希望代码可读性强。我尝试记录每个函数的参数。特别是, 的第一个参数\sort
是比较器控制序列,必须采用三个参数。前两个是以下列表中要比较的两个元素,第三个是延续。基本上,比较器应该根据“小于”扩展为#3{#1}{#2}
或。#3{#2}{#1}
#1
#2
我已经实现了三个这样的比较器。前两个比较数字列表,而第三个使用 进行字母数字字符串比较\pdfstrcmp
。由于数字比较使用,\ifnumcomp
因此etoolbox
您可以对元素使用任意算术表达式,因此{8/2}
在列表中。
最后,为了表明这是可扩展的(至少当比较器、\sortoutput
和为时它是可扩展\sortend
的),\temp
使用来定义\edef
,并且对其含义进行排版以确保它已被设置为适当的值:macro:->12346778955
。
请注意,将这些宏串联起来也很简单,这样就可以在同一个扩展中使用多个宏\sortoutput
。我只是在编写完其余所有代码(或多或少)后才想到添加这些宏。\sortend
\sorts
进一步注意,这是选择排序,因此需要Θ(n2)时间,即使在最好的情况下。然而,这是 TeX,它每次都必须为每个参数构建标记列表,我认为这种实现实际上是Θ(n3)时间。所以不要在大型列表上尝试。
答案2
以下肯定适用于一列表,但我不确定如何将其扩展为多个排序列表。
\documentclass[a4paper,12pt]{report}
\usepackage{datatool}
\usepackage[top=2cm, bottom=2cm, left=1cm, right=1cm]{geometry}
\usepackage[spanish]{babel}
\usepackage{amsfonts,amssymb,amsmath}
\newcommand{\sortitem}[2]{%
\DTLnewrow{list}%
\DTLnewdbentry{list}{label}{#1}%
\DTLnewdbentry{list}{description}{#2}%
}
\newenvironment{sortedlist}{%
\DTLifdbexists{list}{\DTLcleardb{list}}{\DTLnewdb{list}}%
}{%
\DTLsort{label}{list}%
\begin{description}%
\DTLforeach*{list}{\theLabel=label,\theDesc=description}{%
\item[\theLabel] \theDesc }%
\end{description}%
}
\begin{document}
\begin{sortedlist}
\sortitem{Leonard Euler}{Mathematician}
\sortitem{Carl Friedrich Gauss}{Mathematician}
\sortitem{August Ferdinand M"\obius}{Mathematician}
\end{sortedlist}
\end{document}
答案3
如果您愿意使用 LuaLaTeX,那么您应该可以从 ConTeXt MkIV 移植各种特定于语言的排序函数。例如,请参阅
答案4
我开始使用 TH 的代码,发现它需要根据我的用例进行一些调整。具体来说,我希望能够对\par
其中的内容进行排序,并且希望排序顺序是基于\ref
经过一番努力,我终于找到了一些方法,并认为值得在这里分享我的努力成果。使用它的示例文档如下所示:
\documentclass{article}
\usepackage{sort}
\begin{document}
\newcounter{foo}
\refstepcounter{foo}\label{a}
\refstepcounter{foo}\label{b}
\begin{trivlist}
\sortref{%
{{a}{Text with some proofs about part a
in multiple paragraphs!}}%
{{b}{Proofs about
the other part}}%
}
\end{trivlist}
\end{document}
这两个证明将根据 s 的\label
出现顺序自动重新排序。主要区别在于增加了\long
几个位置,使用\newcommand
代替\newcommand*
,并添加了一个新的\sortoutput
使用\getrefnumber
(注意从其参数中修剪)。这些更改后\par
的完整内容为:sort.sty
\usepackage{etoolbox}
\usepackage{refcount}
\makeatletter
% #1 - comparator
% #2 - token list to sort
\newcommand\sort[2]{%
\ifstrempty{#2}
{}% else
{%
\sort@begin#1{}#2\sort@s\sort@begin
}%
}
% helpers
\def\sort@s{\sort@s}
\long\def\ifsort@s#1{%
\ifx\sort@s#1%
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
}
% #1 - comparator
% #2 - tokens processed so far
% #3 - smallest token so far
% #4 - rest of the list
\long\def\sort@begin#1#2#3#4\sort@begin{%
\ifsort@s{#4}
{%
\sortend{#3}%
\sort#1{#2}%
}% else
{%
\sort@go#1{#2}{#3}#4\sort@go
}%
}
% #1 - comparator
% #2 - tokens processed so far
% #3 - smallest token so far
% #4 - token under consideration
% #5 - rest of the list
\long\def\sort@go#1#2#3#4#5\sort@go{%
#1{#3}{#4}{\sort@output#1{#2}{#5}}%
}
% #1 - comparator
% #2 - tokens processed so far
% #3 - rest of the list
% #4 - smaller of the two tokens
% #5 - larger of the two tokens
\long\def\sort@output#1#2#3#4#5{%
\ifsort@s{#3}
{%
\sortoutput{#4}%
\sort#1{#2{#5}}%
}% else
{%
\sort@begin#1{#2{#5}}{#4}#3\sort@begin
}%
}
\def\sort@numlt#1#2#3{%
\ifnumcomp{#1}<{#2}
{#3{#1}{#2}}% else
{#3{#2}{#1}}%
}
\def\sort@numgt#1#2#3{%
\ifnumcomp{#1}>{#2}
{#3{#1}{#2}}% else
{#3{#2}{#1}}%
}
\def\sort@alpha#1#2#3{%
\ifnumcomp{\pdfstrcmp{#1}{#2}}<{0}
{#3{#1}{#2}}% else
{#3{#2}{#1}}%
}
\long\def\fst#1#2{#1}
\long\def\snd#1#2{#2}
\long\def\sort@ref#1#2#3{%
% Since #1 and #2 frequently contain newlines in their \snd part, and
% \getrefnumber is not \long, we must take care to remove any newlines
% *before* supplying an argument to \getrefnumber
\edef\@leftref{\fst#1}%
\edef\@rightref{\fst#2}%
\ifnumcomp{\getrefnumber\@leftref}<{\getrefnumber\@rightref}%
{#3{#1}{#2}}%
{#3{#2}{#1}}%
}
\newcommand*\sortnumlt{\sort\sort@numlt}
\newcommand*\sortnumgt{\sort\sort@numgt}
\newcommand*\sortalpha{\sort\sort@alpha}
\newcommand\sortref{\sort\sort@ref}
% Change these to change out the sort outputs.
\newcommand\sortoutput[1]{%
% As in the definition of \sort@ref, we must take care to remove
% newlines before handing off to \ref
\edef\@refname{\fst#1}%
\item {\bf Case \ref\@refname:} \snd#1%
}
\newcommand\sortend\sortoutput
\makeatother