TeX - LaTeX Asked on October 18, 2020
I have a long number of people to acknowledge in my thesis, and I was wondering if it would be possible to sort their names automatically, rather than doing it by hand. In other words, I would like a macro, say sorted
, which would take
sorted{Gauss, Carl Friedrich and Riemann, Bernhard and Euler, Leonhard}
and output
Leonard Euler, Carl Friedrich Gauss and Bernhard Riemann
To be clear, I am not looking to sort the items in a list environment. Rather, I would like to output a sentence that contains the various names, in alphabetical order. All names but the last two should be separated by a ,
, while the last two should be separated by and
.
Is this what you want? I define some ordering rule:
You can also define your owner ordering rule.
documentclass{article}
usepackage{xparse}
ExplSyntaxOn
tl_new:N l__seq_sep_tl
seq_new:N l__alph_seq
seq_new:N l__Alph_seq
seq_new:N l__Alphalpa_seq
seq_new:N l__alphAlph_seq
seq_new:N l__ralph_seq
seq_new:N l__rAlph_seq
seq_new:N l__rAlphalpa_seq
seq_new:N l__ralphAlph_seq
seq_new:N l__result_seq
seq_new:N l__custom_order_seq
bool_new:N l__if_less_bool
prop_new:N l__order_prop
seq_set_from_clist:Nn l__alph_seq
{ a,b,c,d,e,f,g,h,i,g,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z }
seq_set_from_clist:Nn l__Alph_seq
{ A,B,C,D,E,F,G,H,I,G,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z }
seq_set_from_clist:Nn l__Alphalph_seq
{
A,B,C,D,E,F,G,H,I,G,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,
a,b,c,d,e,f,g,h,i,g,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z
}
seq_set_from_clist:Nn l__alphAlph_seq
{
a,b,c,d,e,f,g,h,i,g,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,
A,B,C,D,E,F,G,H,I,G,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z
}
seq_set_eq:NN l__ralph_seq l__alph_seq
seq_set_eq:NN l__rAlph_seq l__Alph_seq
seq_set_eq:NN l__ralphAlph_seq l__alphAlph_seq
seq_set_eq:NN l__rAlphalph_seq l__Alphalph_seq
seq_reverse:N l__ralph_seq
seq_reverse:N l__rAlph_seq
seq_reverse:N l__ralphAlph_seq
seq_reverse:N l__rAlphalph_seq
seq_set_eq:NN l__custom_order_seq l__Alphalph_seq
prop_set_from_keyval:Nn l__order_prop
{
a = alph,
A = Alph,
aA = alphAlph,
Aa = Alphalph,
ra = ralph,
rA = rAlph,
raA = ralphAlph,
rAa = rAlphalph,
}
keys_define:nn { sort }
{
order .code:n = { set_order_from_option:n { #1 } },
sep .tl_set:N = l__seq_sep_tl,
}
cs_new_protected:Nn set_sort_order_from_seq:N
{
int_zero:N l_tmpa_int
seq_remove_duplicates:N #1
seq_map_inline:Nn #1
{
int_incr:N l_tmpa_int
int_if_exist:cF { g__sort_##1 }
{
int_new:c { g__sort_##1 }
}
int_gset_eq:cN { g__sort_##1 } l_tmpa_int
}
}
prg_new_protected_conditional:Nnn str_if_less:nn { T, F, TF }
{
int_set:Nn l_tmpa_int
{ str_count_ignore_spaces:n { #1 } }
int_set:Nn l_tmpb_int
{ str_count_ignore_spaces:n { #2 } }
int_compare:nTF { l_tmpa_int < l_tmpb_int }
{ bool_set_true:N l__if_less_bool }
{ bool_set_false:N l__if_less_bool }
int_step_inline:nn { int_min:nn { l_tmpa_int } { l_tmpb_int } }
{
int_set_eq:Nc l_tmpa_int
{ g__sort_str_item:nn { #1 } { ##1 } }
int_set_eq:Nc l_tmpb_int
{ g__sort_str_item:nn { #2 } { ##1 } }
int_compare:nF { l_tmpa_int = l_tmpb_int }
{
int_compare:nTF { l_tmpa_int < l_tmpb_int }
{ bool_set_true:N l__if_less_bool }
{ bool_set_false:N l__if_less_bool }
prg_break:
}
}
bool_if:NTF l__if_less_bool
{ prg_return_true: }
{ prg_return_false: }
}
% #1 seq to be sorted #2 predefined order seq
cs_new_protected:Nn seq_sort_by_order:NN
{
set_sort_order_from_seq:N #2
seq_sort:Nn #1
{
str_if_less:nnTF { ##1 } { ##2 }
{ sort_return_same: }
{ sort_return_swapped: }
}
}
cs_generate_variant:Nn seq_set_split:Nnn { Nxo }
cs_new_protected:Nn sort_custom_seq:nn
{
keys_set:nn { sort }
{
sep = {,},
#1
}
seq_set_split:Nxo l__result_seq { l__seq_sep_tl } { #2 }
seq_sort_by_order:NN l__result_seq l__custom_order_seq
}
% #1 seq handle function #2 options #3 list
cs_new_protected:Nn sort_custom_seq:Nnn
{
sort_custom_seq:nn { #2 } { #3 }
#1 l__result_seq
}
cs_new_protected:Nn my_transpose:N
{
seq_clear_new:N l__new_seq
seq_map_inline:Nn #1
{
seq_clear_new:N l__item_seq
seq_set_split:Nnn l__item_seq { , } { ##1 }
seq_reverse:N l__item_seq
seq_put_right:Nx l__new_seq { seq_use:Nn l__item_seq { ~ } }
}
seq_set_eq:NN #1 l__new_seq
}
cs_new_protected:Nn set_order_from_seq:nn
{
seq_set_split:Nnn l__custom_order_seq { #1 } { #2 }
}
cs_new_protected:Nn set_order_from_str:n
{
str_set:Nn l_tmpa_str { #1 }
seq_clear:N l__custom_order_seq
str_map_inline:Nn l_tmpa_str
{
seq_put_right:Nn l__custom_order_seq { ##1 }
}
}
cs_new_protected:Nn set_order_from_option:n
{
prop_if_in:NnTF l__order_prop { #1 }
{
seq_set_eq:Nc l__custom_order_seq
{ l__prop_item:Nn l__order_prop { #1 }_seq }
}
{
set_order_from_str:n { #1 }
}
}
NewDocumentCommand { setorder } { o m }
{
IfNoValueTF { #1 }
{ set_order_from_str:n { #2 } }
{ set_order_from_seq:nn { #1 } { #2 } }
}
NewDocumentCommand { mysorted } { O{} +m }
{
sort_custom_seq:Nnn my_transpose:N { #1 } { #2 }
seq_use:Nnnn l__result_seq { ~and~ } { ,~ } { ~and~ }
}
NewDocumentCommand { sorted } { m +m }
{
sort_custom_seq:nn { order = #1 } { #2 }
makebox[4cm][l]{bfseries Order:~#1}
seq_map_inline:Nn l__result_seq
{
makebox[1.2cm][l]{##1}
}
}
ExplSyntaxOff
begin{document}
mysorted[sep=and]{Gauss, Carl Friedrich and Riemann, Bernhard and Euler, Leonhard}
deftest{app, band, apple, Apple, App}
sorted{aA}{test}
sorted{raA}{test}
sorted{Aa}{test}
sorted{rAa}{test}
sorted{ab-+*@c}{abc, c@-, b+@, @cb, b-c}
end{document}
Correct answer by ZhiyuanLck on October 18, 2020
This is not a complete answer, but the question is not complete, either. As in my comment above, I am basing this answer on this question: Alphabetically display the items in itemize
I changed three lines in the preamble: in essence, there is no need to output a list, just because you input as list. I think that was your biggest issue with my comment.
documentclass{article}
usepackage{datatool}% http://ctan.org/pkg/datatool
newcommand{sortitem}[1]{%
DTLnewrow{list}% Create a new entry
DTLnewdbentry{list}{description}{#1}% Add entry as description
}
newenvironment{sortedlist}{%
DTLifdbexists{list}{DTLcleardb{list}}{DTLnewdb{list}}% Create new/discard old list
}{%
DTLsort{description}{list}% Sort list
%begin{itemize}% THIS LINE CHANGED
DTLforeach*{list}{theDesc=description}{%
theDesc{} and }% THIS LINE CHANGED
%end{itemize}% THIS LINE CHANGED
}
begin{document}
begin{sortedlist}
sortitem{Gauss, Carl Friedrich}
sortitem{Riemann, Bernhard}
sortitem{Euler, Leonhard}
end{sortedlist}
end{document}
This outputs
Euler, Leonhard and Gauss, Carl Friedrich and Riemann, Bernhard and
Your remaining, implicit parts of question (output list separated by commas and "and") are probably answered in Iterating through comma-separated arguments or Special handling of first and/or last item in an etoolbox list.
Answered by bers on October 18, 2020
Bubble sorter, which I adapt from my modification to David's answer to my question at Trying to eliminate stack overflow during recursion.
The sortlist
macro is the bubble sorter (from the referenced answer, but with and
rather than ,
as the list seperator). However, it leaves the result in the form of Last Name, First and ...
.
I had to add the rework
macro to make it First Last Name
and employ whichsep
to choose whether a ,
or and
should be inserted between names, depending on their placement in the list.
No packages required!
documentclass[10pt]{article}
newcommandalphabubblesort[1]{defsortedlist{}%
expandaftersortlist#1 and cr and relax
expandafterreworksortedlist and relax}
defsortlist#1and #2and #3relax{%
letnextrelax
ifxcr#2relax%
edefsortedlist{sortedlist#1}%
else
picknext#1!and #2!relax%
if Fflipflop%
edefsortedlist{sortedlist#1and }%
defnext{sortlist#2and #3relax}%
else%
lettmpsortedlist%
defsortedlist{}%
defnext{expandaftersortlisttmp#2and #1and #3relax}%
fi%
fi%
next
}
defpicknext#1#2and #3#4relax{%
ifnumthelccode`#1<thelccode`#3relax
xdefflipflop{F}%
else%
ifnumthelccode`#1>thelccode`#3relax%
xdefflipflop{T}%
else%
ZZfifi{picknext#2!and #4!relax}%
fi%
fi%
}
defZZfifi#1fifi{fifi#1}
defrework#1, #2and #3relax{#2#1ifxrelax#3relaxelse
whichsep#3,relaxrework#3relaxfi}
defwhichsep#1,#2,#3relax{ifxrelax#3relax and else, fi}
begin{document}
defmydata{%
Gauss, Carl Friedrich and Riemann, Bernhard and Euler, Leonhard}
alphabubblesort{mydata}
I wish to thank
alphabubblesort{%
Gauss, Carl Friedrich and
Riemann, Bernhard and
Euler, Leonhard and
Bach, Carl Philipp Emanuel and
Dumbledore, Albus Percival Wulfric Brian and
Granger, Hermione Jean and
Scott Thomas, Kristin and
Van Gogh, Vincent and
Sartre, Jean-Paul and
Toulouse-Lautrec, Henri de}
for their valuable comments and incisive critiques.
end{document}
Answered by Steven B. Segletes on October 18, 2020
Here's a LuaLaTeX based solution. It sets up a LaTeX macro called sorted
, which calls a Lua function called sorted
to do most of the work. The word and
is taken to be the keyword that separates persons, while ,
(comma) is the separator between the surname and given-name portions of a full name. Space characters and hyphen characters are allowed in both the given-name and first-name portions of a full name.
% !TeX program = lualatex
documentclass{article}
%% Lua-side code
usepackage{luacode} % for 'luacode' environment
begin{luacode}
function string_to_table ( str )
local namelist = {} -- initialize the table
str:gsub ( "([^;]*)" , function ( name )
-- Strip off any leading and trailing whitespace:
name = name:gsub ( "^%s*(.-)%s*$" , "%1" )
-- Insert 'name' in 'namelist'
table.insert ( namelist , name )
end )
return namelist
end
function sorted ( s )
local t
-- Change the separator keyword "and" to ";"
s = s:gsub ( "and" , ";" )
-- Convert to a Lua table:
t = string_to_table ( s )
-- Sort the table entries alphabetically:
table.sort ( t )
n = #t -- Retrieve number of entries
-- Change "Surname, FirstName" to "FirstName Surname":
for i=1,n do
t[i] = string.gsub ( t[i] , "([%a%s%-]+)%,%s?(.+)" , "%2 %1" )
end
-- Output a string, using "and" as the final separator
s = t[1]
for i = 2,n-1 do s = s .. ", " .. t[i] end
s = s .. " and " .. t[n]
tex.sprint ( s )
end
end{luacode}
%% LaTeX-side code:
newcommandsorted[1]{directlua{sorted(luastringN{#1})}}
begin{document}
I wish to thank
sorted{Gauss, Carl Friedrich and Riemann,Bernhard and Euler, Leonhard and
Bach, Carl Philipp Emanuel and Dumbledore,Albus Percival Wulfric Brian and
Granger, Hermione Jean and Scott Thomas, Kristin and Van Gogh, Vincent and
Sartre, Jean-Paul and Toulouse-Lautrec, Henri de}
for their valuable comments and incisive critiques.
end{document}
Answered by Mico on October 18, 2020
Get help from others!
Recent Questions
Recent Answers
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP