
En mi archivo LaTeX creo una variable \authors
que podría tener contenido:
[Doe] John Doe; [Potter] Harry Potter; [Clinton] Bill Clinton; [Obama] Barack Obama; ...
Esto se crea dinámicamente, por lo que podría variarlo un poco (tengo un archivo de datos del cual recupero el nombre y apellido). ¿Hay alguna manera de convertir este texto variable en una lista ordenada (por apellido) y claramente mostrada?
Bill Clinton, John Doe, Barack Obama, Harry Potter,...
1) ¿es esto posible? 2) ¿debería almacenar esta información inicial en una variable o debería almacenarla en un archivo o en algo más?
Respuesta1
Aquí hay una implementación usando expl3
y el módulo 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}
Se agrega un autor con \addauthor{<first name(s)>}{<last name>}
; se permite un argumento opcional para tratar con caracteres especiales; Este argumento opcional se utilizará tanto para indexar las listas de propiedades como para ordenarlas.
VerOrdenar las subsecciones alfabéticamentepara otra aplicación de\seq_sort:Nn
Si tiene dos autores con el mismo apellido, utilice el argumento opcional; Por ejemplo
\addauthor[Doe@Jane]{Jane}{Doe}
\addauthor[Doe@John]{John}{Doe}
Tenga en cuenta que el argumento opcional determina el orden de clasificación; El uso de @
, que aparece antes de las letras en ASCII, garantizará que los dos autores de Doe se ordenen antes de "Doeb". Se podría usar la misma idea para todos los autores, es decir, usar “lname@fname” como clave de clasificación, pero esto daría problemas con los caracteres especiales en el nombre.
Aquí hay una versión que no agrega un autor si la clave de clasificación (apellido o argumento opcional) ya está presente en la base de datos.
\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}
La ejecución de este archivo producirá una advertencia como
*************************************************
* konewka/authors warning: "author exists"
*
* The author Doe already exists; it won't be added again
*************************************************
Cambie \msg_warning:nnn
a \msg_error:nnn
si prefiere que se genere un error en lugar de que se emita una advertencia.
Respuesta2
Solo a modo ilustrativo, muestro cómo resolver esta tarea en TeX simple usando la macro OPmac donde se implementa mergesort.
\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
La clasificación se realiza según los datos encerrados entre [corchetes] pero los datos fuera de [corchetes] se imprimen. OPmac permite el soporte multilingüe de clasificación.