1

In How to sort an alphanumeric list , there is a nice and short sort facility, which I am reproducing here:

%% from https://tex.stackexchange.com/questions/6988/how-to-sort-an-alphanumeric-list

\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

\newcommand\sortoutput[1]{#1 $\rightarrow$ } \newcommand\sortend[1]{#1. $\leftarrow$ }

I stuck the above into a sort.sty file, and now I am trying to use it on a sample.

\documentclass{article}

\usepackage{sort}

\def\mystring{} \makeatletter\def\addstring#1{\g@addto@macro\mystring{ #1}}\makeatother

\begin{document}

Sorted Literals: \sortalpha{{Goodbye, 1}{Cruel, 2}{World, 3}}

\bigskip

\addstring{goodbye, \pageref{pg:goodbye}.} \label{pg:goodbye} \addstring{cruel, \pageref{pg:cruel}.} \label{pg:cruel} \addstring{world, \pageref{pg:world}.} \label{pg:world}

Collected: \texttt{\mystring}

Sorted Collected: \sortalpha{\mystring}

\end{document}

The output is appropriately sorted for the literals, but not for the contents of the string. \expandafter before \mystring does not seem to do it, either.

unsorted output

I hope the magic to accomplish this on the contents of the macro is simple. help appreciated.

PS: I admit to wanting to create my own little sorted keyword index (with simple sequential running rather than more fancy formatting) at the end of my latex file without having to invoke an external program like \makeindex. I may also need to add a \MakeUppercase.

ivo Welch
  • 3,766
  • In general, \expandafter\sortalpha\expandafter{\mystring} would be required to sort the contents of \mystring. Also, your \addstring definition should be \g@addto@macro\mystring{{#1}}} to mimic your literal case input. Finally, there seems to be an issue when doing what I say on the first pass, because \pageref is still not sorted out. But once you can get the aux file written properly, what I suggest works. – Steven B. Segletes Nov 03 '21 at 02:26
  • ... you know, there's no magic and there's no easy way to program. Understand the code you copy-pasted properly before trying to edit it. -- Or just write your own with expl3. – user202729 Nov 03 '21 at 05:42
  • Thx, Steven. Weird problem: When the \pageref is to a non-existent label (as it is on the first pass), latex blocks with ! Undefined control sequence. \reserved@a ->\@nil at the \expandafter\sortalpha\expandafter{\mystring}. I had hoped that \pageref would just produce the standard '??' text on the first run and the correct page number on the second run, but instead the \expandafter completely blocks the first run. Easy fix? – ivo Welch Nov 03 '21 at 05:51
  • Following https://tex.stackexchange.com/questions/111311/how-to-make-a-conditional-reference-to-a-text-label you can do \def\chkpageref#1{\@ifundefined{r@#1}{0}{\pageref{#1}}} and then \addstring{goodbye, \chkpageref{pg:goodbye}.}. – Marijn Nov 03 '21 at 09:27

1 Answers1

1

This just summarizes Steven Segletes and Marijn's answers. Thank you to both of you.

\documentclass{article}

\usepackage{sort}

\makeatletter \def\mykeywords{} \def\kwclear{\def\mykeywords{}} \def\addkeyword#1{\g@addto@macro\mykeywords{{#1}}} \def\chkpageref#1{@ifundefined{r@#1}{na}{\pageref{#1}}} \def\kw#1{\textbf{#1}\addkeyword{#1, p.\chkpageref{pg:#1}}\label{pg:#1}} \def\kwprint{\par\textbf{Keywords: } \expandafter\sortalpha\expandafter{\mykeywords}\par} \makeatother

\begin{document}

\kwclear

The text is hello and \kw{goodbye}. \kw{cruel} people are in this \kw{world}.

\bigskip

\kwprint

\end{document}

yields

enter image description here

and for completeness the sort.sty again:

%% from https://tex.stackexchange.com/questions/6988/how-to-sort-an-alphanumeric-list

\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

\newcommand\sortoutput[1]{#1 $\rightarrow$ } \newcommand\sortend[1]{#1. $\leftarrow$ }

ivo Welch
  • 3,766