Zum Sortieren einer Zeichenfolge mit mehreren Einträgen

Zum Sortieren einer Zeichenfolge mit mehreren Einträgen

In meiner LaTeX-Datei erstelle ich eine Variable \authors, die Inhalt haben könnte:

[Doe] John Doe; [Potter] Harry Potter; [Clinton] Bill Clinton; [Obama] Barack Obama; ...

Dies wird dynamisch erstellt, sodass ich es ein wenig variieren kann (ich habe eine Datendatei, aus der ich die Vor- und Nachnamen abrufe). Gibt es eine Möglichkeit, diesen variablen Text in eine geordnete (nach Nachnamen) und übersichtlich angezeigte Liste umzuwandeln?

Bill Clinton, John Doe, Barack Obama, Harry Potter,...

1) ist dies möglich? 2) soll ich diese Anfangsinformationen in einer Variablen speichern oder soll ich sie in einer Datei oder etwas anderem speichern?

Antwort1

Hier ist eine Implementierung expl3mit dem Modul l3sort:

\documentclass{article}

\usepackage{xparse,l3sort,pdftexcmds}

\ExplSyntaxOn

\cs_set_eq:Nc \konewka_strcmp:nn { pdf@strcmp }

\NewDocumentCommand{\addauthor}{ o m m }
 {
  \IfNoValueTF{#1}
   {
    \konewka_add_author:nnn { #3 } { #2 } { #3 }
   }
   {
    \konewka_add_author:nnn { #1 } { #2 } { #3 }
   }
 }

\NewDocumentCommand{\printauthors}{ }
 {
  \konewka_print_authors:
 }

\seq_new:N \g_konewka_authors_id_seq
\seq_new:N \l__konewka_authors_full_seq

\cs_new_protected:Npn \konewka_add_author:nnn #1 #2 #3
 {
  \seq_gput_right:Nn \g_konewka_authors_id_seq { #1 }
  \prop_new:c { g_konewka_author_#1_prop }
  \prop_gput:cnn { g_konewka_author_#1_prop } { fname } { #2 }
  \prop_gput:cnn { g_konewka_author_#1_prop } { lname } { #3 }
 }

\cs_new_protected:Npn \konewka_print_authors:
 {
  \seq_gsort:Nn \g_konewka_authors_id_seq
   {
    \string_compare:nnnTF {##1} {>} {##2} {\sort_reversed:} {\sort_ordered:}
   }
  \seq_clear:N \l__konewka_authors_full_seq
  \seq_map_inline:Nn \g_konewka_authors_id_seq
   {
    \seq_put_right:Nx \l__konewka_authors_full_seq
     {
      \prop_item:cn { g_konewka_author_##1_prop } { fname }
      \c_space_tl
      \prop_item:cn { g_konewka_author_##1_prop } { lname }
     }
   }
  \seq_use:Nn \l__konewka_authors_full_seq { ,~ }
 }

\prg_new_conditional:Npnn \string_compare:nnn #1 #2 #3 {TF}
  {
   \if_int_compare:w \konewka_strcmp:nn {#1}{#3} #2 \c_zero
    \prg_return_true:
   \else:
    \prg_return_false:
   \fi
  }

\ExplSyntaxOff

\begin{document}

\addauthor{John}{Doe}
\addauthor{Harry}{Potter}
\addauthor[Uthor]{Archibald}{\"Uthor}
\addauthor{Bill}{Clinton}
\addauthor{Barack}{Obama}

\printauthors

\end{document}

Ein Autor wird mit hinzugefügt \addauthor{<first name(s)>}{<last name>}; zum Umgang mit Sonderzeichen ist ein optionales Argument zulässig; dieses optionale Argument wird sowohl zum Indizieren der Eigenschaftenlisten als auch zum Sortieren verwendet.

Bildbeschreibung hier eingeben

SehenUnterabschnitte alphabetisch sortierenfür eine andere Anwendung von\seq_sort:Nn

Wenn Sie zwei Autoren mit demselben Nachnamen haben, verwenden Sie das optionale Argument. Beispiel:

\addauthor[Doe@Jane]{Jane}{Doe}
\addauthor[Doe@John]{John}{Doe}

Beachten Sie, dass das optionale Argument die Sortierreihenfolge bestimmt. Die Verwendung von @, das in ASCII vor Buchstaben steht, garantiert, dass die beiden Autoren „Doe“ vor „Doeb“ sortiert werden. Man könnte dieselbe Idee für alle Autoren verwenden, d. h. „lname@fname“ als Sortierschlüssel verwenden, aber dies würde zu Problemen mit Sonderzeichen im Vornamen führen.

Hier ist eine Version, die keinen Autor hinzufügt, wenn der Sortierschlüssel (Nachname oder optionales Argument) bereits in der Datenbank vorhanden ist.

\documentclass{article}

\usepackage{xparse,l3sort,pdftexcmds}

\ExplSyntaxOn

\cs_set_eq:Nc \konewka_strcmp:nn { pdf@strcmp }

\NewDocumentCommand{\addauthor}{ o m m }
 {
  \IfNoValueTF{#1}
   {
    \konewka_add_author:nnn { #3 } { #2 } { #3 }
   }
   {
    \konewka_add_author:nnn { #1 } { #2 } { #3 }
   }
 }

\NewDocumentCommand{\printauthors}{ }
 {
  \konewka_print_authors:
 }

\seq_new:N \g_konewka_authors_id_seq
\seq_new:N \l__konewka_authors_full_seq

\msg_new:nnn { konewka/authors } { author~exists }
 {
  The ~ author ~ #1 ~ already ~ exists; ~ it ~ won't ~ be ~ added ~ again
 }

\cs_new_protected:Npn \konewka_add_author:nnn #1 #2 #3
 {
  \prop_if_exist:cTF { g_konewka_author_#1_prop }
   {
    \msg_warning:nnn { konewka/authors } { author~exists } { #1 }
   }
   {
    \seq_gput_right:Nn \g_konewka_authors_id_seq { #1 }
    \prop_new:c { g_konewka_author_#1_prop }
    \prop_gput:cnn { g_konewka_author_#1_prop } { fname } { #2 }
    \prop_gput:cnn { g_konewka_author_#1_prop } { lname } { #3 }
   }
 }

\cs_new_protected:Npn \konewka_print_authors:
 {
  \seq_gsort:Nn \g_konewka_authors_id_seq
   {
    \string_compare:nnnTF {##1} {>} {##2} {\sort_reversed:} {\sort_ordered:}
   }
  \seq_clear:N \l__konewka_authors_full_seq
  \seq_map_inline:Nn \g_konewka_authors_id_seq
   {
    \seq_put_right:Nx \l__konewka_authors_full_seq
     {
      \prop_item:cn { g_konewka_author_##1_prop } { fname }
      \c_space_tl
      \prop_item:cn { g_konewka_author_##1_prop } { lname }
     }
   }
  \seq_use:Nn \l__konewka_authors_full_seq { ,~ }
 }

\prg_new_conditional:Npnn \string_compare:nnn #1 #2 #3 {TF}
  {
   \if_int_compare:w \konewka_strcmp:nn {#1}{#3} #2 \c_zero
    \prg_return_true:
   \else:
    \prg_return_false:
   \fi
  }

\ExplSyntaxOff

\begin{document}

\addauthor{John}{Doe}
\addauthor{Harry}{Potter}
\addauthor[Uthor]{Archibald}{\"Uthor}
\addauthor{John}{Doe}
\addauthor{Bill}{Clinton}
\addauthor{Barack}{Obama}

\printauthors

\end{document}

Beim Ausführen dieser Datei wird eine Warnung wie diese ausgegeben:

*************************************************
* konewka/authors warning: "author exists"
* 
* The author Doe already exists; it won't be added again
*************************************************

Ändern Sie \msg_warning:nnnes in \msg_error:nnn, wenn Sie möchten, dass ein Fehler ausgelöst und keine Warnung ausgegeben wird.

Antwort2

Nur zur Veranschaulichung zeige ich, wie diese Aufgabe in reinem TeX mithilfe des OPmac-Makros gelöst werden kann, in dem Mergesort implementiert ist.

\input opmac

\def\sort{\begingroup\setprimarysorting\def\iilist{}\sortA}
\def\sortA#1#2{\ifx\relax#1\sortB\else
  \expandafter\addto\expandafter\iilist\csname,#1\endcsname
  \expandafter\preparesorting\csname,#1\endcsname
  \expandafter\edef\csname,#1\endcsname{{\tmpb}{#2}}%
  \expandafter\sortA\fi
}
\def\sortB{\def\message##1{}\dosorting
  \def\act##1{\ifx##1\relax\else \seconddata##1\sortC \expandafter\act\fi}%
  \gdef\tmpb{}\expandafter\act\iilist\relax
  \endgroup
}
\def\sortC#1&{\global\addto\tmpb{{#1}}}

\def\printauthors{\def\tmp{}\expandafter\printauthorsA\authors [] {} {}; }
\def\printauthorsA [#1] #2 #3; {%
   \ifx^#1^\expandafter\sort\tmp\relax\relax
           \def\tmp{}\expandafter\printauthorsB\tmpb\relax  
   \else\addto\tmp{{#1}{#2 #3}}\expandafter\printauthorsA\fi
}
\def\printauthorsB#1{\ifx\relax#1\else \tmp\def\tmp{, }#1\expandafter\printauthorsB\fi}

\def\authors{[Doe] John Doe; [Potter] Harry Potter; [Clinton] Bill Clinton;
             [Uthor] Archibald \"Uthor; [Obama] Barack Obama; }

Authors: \printauthors

\bye

Die Sortierung erfolgt nach den in [Klammern] eingeschlossenen Daten, die Daten außerhalb der [Klammern] werden jedoch gedruckt. Die mehrsprachige Unterstützung der Sortierung ist durch OPmac möglich.

verwandte Informationen