使用 LaTeX 对逗号分隔的列表进行排序?

使用 LaTeX 对逗号分隔的列表进行排序?

在 LaTeX 中,有没有一种简单的方法可以按字母顺序对逗号分隔的列表进行排序?我尝试\sortlist{World, Hello}使用文档示例编写一个宏(→“Hello, World”)l3sort,但完全失败了。

\ExplSyntaxOn
\def\@sortlist{}
\newcommand{\sortlist}[1]{
    \clist_set:Nn \l_foo_clist {#1}
    \clist_sort:Nn \l_foo_clist{
      \int_compare:nNnTF { ##1 } > { ##2 }
      { \sort_return_swapped: }
      { \sort_return_same: }
    }
    \def\@sortlist{\l_foo_clist}
}
\ExplSyntaxOff

是否有类似\str_compare进行字符串比较或l3sort实际上只能用于数值的方法?

编辑:
如何处理以逗号分隔的列表?对我来说并没有什么帮助,或者说我无法解决我的问题。

答案1

这似乎有效,无需任何软件包。已编辑以解决大小写问题。

编辑:解决了在解决订单之前比较用尽字母时出现的问题,例如wash, washer

附录用于(以某种方式)处理变音符号。

\documentclass{article}
\def\listterminator{;}
\makeatletter
\newcommand\alphabubblesort[1]{\def\presorted{}\def\sortedlist{}%
  \sortlist#1,\listterminator,\relax}
\def\sortlist#1#2,#3#4,#5\relax{%
  \if\listterminator#3#4\relax%
    \edef\sortedlist{\sortedlist#1#2}%
  \else
    \ifnum\the\lccode`#1<\the\lccode`#3\relax%
      \edef\sortedlist{\sortedlist\presorted#1#2, }%
      \expandafter\def\expandafter\svfirst\expandafter{\presorted#3#4}%
      \def\presorted{}%
      \expandafter\sortlist\svfirst,#5\relax%
    \else%
      \ifnum`#1=`#3\relax%
        \ifx\relax#2\relax%
          \edef\sortedlist{\sortedlist\presorted#1#2, }%
          \expandafter\def\expandafter\svfirst\expandafter{\presorted#3#4}%
          \def\presorted{}%
          \expandafter\sortlist\svfirst,#5\relax%          
        \else%
          \ifx\relax#4\relax%
            \edef\sortedlist{\sortedlist\presorted#3#4, }%
            \expandafter\def\expandafter\svfirst\expandafter{\presorted#1#2}%
            \def\presorted{}%
            \expandafter\sortlist\svfirst,#5\relax%
          \else        
            \g@addto@macro\presorted{#1}%
            \sortlist#2,#4,#5\relax%
          \fi%
        \fi%
      \else%
        \let\tmp\sortedlist%
        \def\sortedlist{}%
        \expandafter\def\expandafter\svfirst\expandafter{\presorted#3#4}%
        \expandafter\def\expandafter\svsecond\expandafter{\presorted#1#2}%
        \def\presorted{}%
        \expandafter\expandafter\expandafter\expandafter\expandafter%
        \expandafter\expandafter\sortlist\expandafter\expandafter%
        \expandafter\tmp\expandafter\svfirst\expandafter,\svsecond,#5\relax%
      \fi%
    \fi%
  \fi%
}
\makeatother
\begin{document}
\alphabubblesort{book, boot, boat,toad,attic,wish,wash,wasn't,Cat ,Xylophone}
\sortedlist\par

\alphabubblesort{book, washer, boot, boat,toad,attic,wish,wash,wasn't,Cat ,Xylophone}
\sortedlist\par
\end{document}

在此处输入图片描述

附录

这是一个可以处理变音符号的版本,因为它们不会破坏算法。这是通过将\edef上述算法中的 s 更改为适当扩展的\defs 来实现的。

但是,这里的变音字母在排序时始终位于所有非变音字母之前。虽然这可能不是理想的行为,但仍然很有用。

\documentclass{article}
\def\listterminator{;}
\makeatletter
\newcommand\alphabubblesort[1]{\def\presorted{}\def\sortedlist{}%
  \sortlist#1,\listterminator,\relax}
\def\sortlist#1#2,#3#4,#5\relax{%
  \if\listterminator#3#4\relax%
    \expandafter\def\expandafter\sortedlist\expandafter{\sortedlist#1#2}%
  \else
    \ifnum\the\lccode`#1<\the\lccode`#3\relax%
      \expandafter\expandafter\expandafter\def\expandafter\expandafter%
      \expandafter\sortedlist\expandafter\expandafter\expandafter{%
      \expandafter\sortedlist\presorted#1#2, }%
      \expandafter\def\expandafter\svfirst\expandafter{\presorted#3#4}%
      \def\presorted{}%
      \expandafter\sortlist\svfirst,#5\relax%
    \else%
      \ifnum`#1=`#3\relax%
        \ifx\relax#2\relax%
          \expandafter\expandafter\expandafter\def\expandafter\expandafter%
          \expandafter\sortedlist\expandafter\expandafter\expandafter{%
          \expandafter\sortedlist\presorted#1#2, }%
          \expandafter\def\expandafter\svfirst\expandafter{\presorted#3#4}%
          \def\presorted{}%
          \expandafter\sortlist\svfirst,#5\relax%          
        \else%
          \ifx\relax#4\relax%
            \expandafter\expandafter\expandafter\def\expandafter\expandafter%
            \expandafter\sortedlist\expandafter\expandafter\expandafter{%
            \expandafter\sortedlist\presorted#3#4, }%
            \expandafter\def\expandafter\svfirst\expandafter{\presorted#1#2}%
            \def\presorted{}%
            \expandafter\sortlist\svfirst,#5\relax%
          \else        
            \g@addto@macro\presorted{#1}%
            \sortlist#2,#4,#5\relax%
          \fi%
        \fi%
      \else%
        \let\tmp\sortedlist%
        \def\sortedlist{}%
        \expandafter\def\expandafter\svfirst\expandafter{\presorted#3#4}%
        \expandafter\def\expandafter\svsecond\expandafter{\presorted#1#2}%
        \def\presorted{}%
        \expandafter\expandafter\expandafter\expandafter\expandafter%
        \expandafter\expandafter\sortlist\expandafter\expandafter%
        \expandafter\tmp\expandafter\svfirst\expandafter,\svsecond,#5\relax%
      \fi%
    \fi%
  \fi%
}
\makeatother
\begin{document}
\alphabubblesort{book, washer, w\"asher, boot, boat,toad,attic,wish,wash,wasn't,
  Cat, Xylophone, w\"ash, edifice, \'edifice, w\"asherei}
\sortedlist\par
\end{document}

在此处输入图片描述

该算法基于我的\bubblesort宏:使用 LaTeX 压缩数字列表

答案2

Lua 怎么样?

\def\sortlist#1{%
  \directlua{%
    local t = { #1 }
    table.sort(t)
    tex.sprint(table.concat(t,", "))
  }%
}

\sortlist{"World", "Hello"}

\bye

在此处输入图片描述

附录:这种方法的一个真正有用的优点是它是完全可扩展的,这意味着在

\edef\x{\sortlist{"World", "Hello"}}

该宏\x将包含排序后的列表。


使用 ConTeXt MKIV 时,您可以使用内部设置解析器将逗号分隔列表转换为 Lua 表。这样做的好处是您无需自己处理引号。它还尊重内部逗号的分组。

\def\sortlist#1{%
  \ctxlua{%
    local t = utilities.parsers.settings_to_array("\luaescapestring{#1}")
    table.sort(t)
    tex.sprint(table.concat(t,", "))
  }%
}

\starttext
\sortlist{World, Hello, {Entry, with, commas}, "Quotes"}
\stoptext

在此处输入图片描述

答案3

您可以安全地比较由 ASCII 字符组成的字符串;带有重音字符的单词将不起作用。

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

\ExplSyntaxOn
\prg_new_conditional:Nnn \john_string_if_before:nn { p,T,F,TF }
 {% I hope the LaTeX3 police won't catch me
  \int_compare:nTF { \tex_strcmp:D { #1 } { #2 } < 0 }
   {
    \prg_return_true:
   }
   {
    \prg_return_false:
   }
 }

\NewDocumentCommand{\sortlist}{smm}
 {
  \IfBooleanTF{#1}
   {
    \clist_set:No \l__john_sortlist_data_clist { #2 }
   }
   {
    \clist_set:Nn \l__john_sortlist_data_clist { #2 }
   }
  \john_sortlist:N \l__john_sortlist_data_clist
  \clist_set_eq:NN #3 \l__john_sortlist_data_clist
 }
\clist_new:N \l__john_sortlist_data_clist

\cs_new_protected:Nn \john_sortlist:N
 {
  \clist_sort:Nn #1
   {
    \john_string_if_before:nnTF { ##1 } { ##2 }
     {
      \sort_return_same:
     }
     {
      \sort_return_swapped:
     }
   }
 }
\ExplSyntaxOff

\begin{document}

\sortlist{World,Hello}{\mylistA}

\mylistA

\newcommand{\mylistB}{duck,cat,dog}

\sortlist*{\mylistB}{\mylistC}

\mylistB ${}\to{}$\mylistC

\end{document}

在此处输入图片描述

如果希望比较不区分大小写,请将定义更改\john_sortlist:N

\cs_new_protected:Nn \john_sortlist:N
 {
  \clist_sort:Nn #1
   {
    \john_string_if_before:nnTF { \str_foldcase:n {##1} } { \str_foldcase:n {##2} }
     {
      \sort_return_same:
     }
     {
      \sort_return_swapped:
     }
   }
 }

答案4

你可以尝试一下

这是接管https://tex.stackexchange.com/a/273084/4686(代码 5)

% ------------------------------------------------------------------
% Expandable routine to sort strings, based on a QuickSort algorithm 
% and using \pdfstrcmp.
% ------------------------------------------------------------------

% USAGE
% -----

% if using XeTeX:
% \edef\mysortedlist {\QSfull{\mylist}}, or explicit \QSfull {foo, bar, zoo} 


% if using PDFLaTeX: (and inputenc for accented letters)
% \begingroup
%    \subdueutfviiienc
%    \global\edef\mysortedlist {\QSfull{\mylist}}
% \endgroup


\documentclass{article}

\ifdefined\XeTeXinterchartoks
   \let\pdfstrcmp\strcmp
   \usepackage{fontspec}
\else
   \usepackage[T1]{fontenc}
   \usepackage[utf8]{inputenc}% for PDFLaTeX
   \makeatletter
   % this \subdueutfviiienc allows é, à, etc... to survive as is to \edef's.
   \newcommand*\subdueutfviiienc {% to be used in a group
    \count@="C2
    \loop
        \lccode`~\count@
        \lowercase{\def~####1{\noexpand~\string####1}}%
        \ifnum\count@<"E0
        \advance\count@\@ne
    \repeat
    \loop
        \lccode`~\count@
        \lowercase{\def~####1####2{\noexpand~\string####1\string####2}}%
        \ifnum\count@<"F0
        \advance\count@\@ne
    \repeat
    \loop
        \lccode`~\count@
        \lowercase{\def~####1####2####3{\noexpand~\string####1\string####2\string####3}}%
        \ifnum\count@<"F4
        \advance\count@\@ne
    \repeat
   }\makeatother
   % (if inputenc is used with 8bit encoding another approach would be needed)
\fi



% CODE TAKEN FROM https://tex.stackexchange.com/a/273084/4686 (code 5)
% -------------------------------------------------------------------

\makeatletter
\long\def\xintdothis #1#2\xintorthat #3{\fi #1}%
\let\xintorthat \@firstofone
%
% use some (improbable) tokens as delimiters
\catcode`! 3
\catcode`? 3
\catcode`; 3
%
% first we check if empty list (else \qsfull@finish will not find a comma)
% we apply f-expansion to the argument to allow it to be a macro.
%
\def\QSfull #1{\expandafter\qsfull@a\romannumeral-`0#1,!,?}%
%
% first check if input has only blanks, or is empty
\def\qsfull@a #1{\ifx,#1\xintdothis\qsfull@a\fi
                 \ifx!#1\xintdothis\qsfull@abort\fi
                 \xintorthat{\qsfull@start #1}}%
\def\qsfull@abort #1?{}%
%
\def\qsfull@start {\expandafter\qsfull@finish\romannumeral0\qsfull@b,}%
\def\qsfull@finish ,#1{#1}% remove initial ,<space>

\def\qsfull@b ,#1#2,#3{\ifx?#3\xintdothis\qsfull@emptylist\fi
                       \ifx!#3\xintdothis\qsfull@singleton\fi
                       \xintorthat \qsfull@separate@a {}{}#1#2;#3}%
\def\qsfull@emptylist    #1?{}%
\def\qsfull@singleton    #1#2#3;!,?{, #3}%
%
\def\qsfull@separate@a  #1#2#3;#4#5,%
% first pass, remove blanks in passing.
% no need to be extra efficient for that.
{%
    \ifx,#4\expandafter\qsfull@valueisblank\fi
    \ifx!#4\expandafter\qsfull@separate@done\fi
    \if1\pdfstrcmp{#4#5}{#3}%
         \expandafter\qsfull@separate@a@appendtogreater
    \else\expandafter\qsfull@separate@a@appendtosmaller
    \fi
          #4#5?{#1}{#2}#3;%
}%
\def\qsfull@valueisblank \ifx#1\fi,#2?#3#4#5;{\qsfull@separate@a {#3}{#4}#5;#2,}%
\def\qsfull@separate@a@appendtogreater #1?#2{\qsfull@separate@a {#2, #1}}%
%
\def\qsfull@separate@a@appendtosmaller #1?#2#3{\qsfull@separate@a {#2}{#3, #1}}%
%
\def\qsfull@separate@done\if#1\fi #2?#3#4#5;?%
{%
    \qsfull@c #4,!,?, #5\qsfull@c #3,!,?%
}%
% Now that the first pass is done, there are no more blank items.
% In particular here.
\def\qsfull@c ,#1#2,#3{\ifx?#3\xintdothis\qsfull@emptylist\fi
                       \ifx!#3\xintdothis\qsfull@singleton\fi
                       \xintorthat \qsfull@separate {}{}#1#2;#3}%
%
\def\qsfull@separate  #1#2#3;#4#5,% blanks have already been filtered out.
{%
    \ifx!#4\expandafter\qsfull@separate@done\fi
    \if1\pdfstrcmp{#4#5}{#3}%
         \expandafter\qsfull@separate@a@appendtogreater
    \else\expandafter\qsfull@separate@a@appendtosmaller
    \fi
          #4#5?{#1}{#2}#3;%
}%
\def\qsfull@separate@appendtogreater #1?#2{\qsfull@separate {#2, #1}}%
\def\qsfull@separate@appendtosmaller #1?#2#3{\qsfull@separate {#2}{#3, #1}}%
%
%
\catcode`! 12
\catcode`? 12
\catcode`; 12
\makeatother


\begin{document}

\def\mylist{book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't,
  Cat, Xylophone, wäsh, edifice, édifice, wäsherei}

% use either a macro \mylist or explicit list as \QSfull argument.
\ifdefined\XeTeXinterchartoks
   \edef\mysortedlist{\QSfull{\mylist}}
\else
   {\subdueutfviiienc\global\edef\mysortedlist{\QSfull{\mylist}}}%
\fi

\mylist\par

\medskip

becomes (notice how whitespaces are normalized in the process):

\medskip

\mysortedlist

\medskip
For some reason due to the comparison being done by \verb|\pdfstrcmp| the é
comes after a-z.

% check
\typeout{\meaning\mylist}

\typeout{\meaning\mysortedlist}

\end{document}

在此处输入图片描述

这里是日志输出,使用 PDFLaTeX:

macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xyl
ophone, wäsh, edifice, édifice, wäsherei
macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, w
asn't, wish, wäsh, wäsher, wäsherei, édifice

并使用 XeLaTeX(其切割线条方式不同):

macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xylo
phone, wäsh, edifice, édifice, wäsherei
macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, w
asn't, wish, wäsh, wäsher, wäsherei, édifice

控制台输出(再次是 XeLaTeX)仍然不同,线条没有被切断:

macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xylophone, wäsh, edifice, édifice, wäsherei
macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, wasn't, wish, wäsh, wäsher, wäsherei, édifice

相关内容