О сортировке строки с несколькими записями

О сортировке строки с несколькими записями

В моем LaTeX-файле я создаю переменную, \authorsкоторая может иметь следующее содержимое:

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

Это динамически создается, поэтому я мог бы немного изменить его (у меня есть файл данных, из которого я извлекаю имена и фамилии). Есть ли способ превратить этот переменный текст в упорядоченный (по фамилии) и аккуратно отображаемый список

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

1) возможно ли это, 2) следует ли мне хранить эту исходную информацию в переменной или следует хранить ее в файле или где-то еще?

решение1

Вот реализация с использованием expl3модуля 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}

Автор добавляется с помощью \addauthor{<first name(s)>}{<last name>}; допускается необязательный аргумент для обработки специальных символов; этот необязательный аргумент будет использоваться как для индексации списков свойств, так и для сортировки.

введите описание изображения здесь

ВидетьСортировать подразделы по алфавитудля другого применения\seq_sort:Nn

Если у вас два автора с одинаковой фамилией, используйте необязательный аргумент, например

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

Обратите внимание, что необязательный аргумент определяет порядок сортировки; использование @, который идет перед буквами в ASCII, гарантирует, что два автора Doe будут отсортированы перед «Doeb». Можно использовать ту же идею для всех авторов, то есть использовать «lname@fname» в качестве ключа сортировки, но это приведет к проблемам со специальными символами в имени.

Вот версия, которая не добавляет автора, если ключ сортировки (фамилия или необязательный аргумент) уже присутствует в базе данных.

\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}

Запуск этого файла выдаст предупреждение, например:

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

Измените \msg_warning:nnnна , \msg_error:nnnесли вы предпочитаете, чтобы вместо предупреждения отображалась ошибка.

решение2

Просто для иллюстрации я покажу, как решить эту задачу в простом TeX с использованием макроса OPmac, в котором реализована сортировка слиянием.

\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

Сортировка выполняется по данным, заключенным в [скобки], но данные вне [скобок] выводятся на печать. Многоязычная поддержка сортировки возможна с помощью OPmac.

Связанный контент