Sorting a comma-separated list with LaTeX?
Is there a simple way to sort a comma separated list alphabetically in LaTeX? I tried to write a macro (sortlist{World, Hello}
→ "Hello, World") using the l3sort
documentation example but it completely failed.
ExplSyntaxOn
def@sortlist{}
newcommand{sortlist}[1]{
clist_set:Nn l_foo_clist {#1}
clist_sort:Nn l_foo_clist{
int_compare:nNnTF { ##1 } > { ##2 }
{ sort_return_swapped: }
{ sort_return_same: }
}
def@sortlist{l_foo_clist}
}
ExplSyntaxOff
Is there something like str_compare
to make a string comparison or can l3sort
actually only be used for numerical values?
Edit:
How to process a comma separated list? wasn't really helpful for me or rather I wasn't able to solve my problem thereby.
expl3 sorting comma-separated-list
add a comment |
Is there a simple way to sort a comma separated list alphabetically in LaTeX? I tried to write a macro (sortlist{World, Hello}
→ "Hello, World") using the l3sort
documentation example but it completely failed.
ExplSyntaxOn
def@sortlist{}
newcommand{sortlist}[1]{
clist_set:Nn l_foo_clist {#1}
clist_sort:Nn l_foo_clist{
int_compare:nNnTF { ##1 } > { ##2 }
{ sort_return_swapped: }
{ sort_return_same: }
}
def@sortlist{l_foo_clist}
}
ExplSyntaxOff
Is there something like str_compare
to make a string comparison or can l3sort
actually only be used for numerical values?
Edit:
How to process a comma separated list? wasn't really helpful for me or rather I wasn't able to solve my problem thereby.
expl3 sorting comma-separated-list
3
Welcome to TeX.SX! Knowing a bit more about your failed attempt and the kind of data you need to sort would be helpful.
– egreg
Oct 11 '16 at 11:30
1
Sorting strings of ASCII characters is feasible (although non yet supported byexpl3
); it would become much more complicated if words with accents and so on are involved.
– egreg
Oct 11 '16 at 12:37
add a comment |
Is there a simple way to sort a comma separated list alphabetically in LaTeX? I tried to write a macro (sortlist{World, Hello}
→ "Hello, World") using the l3sort
documentation example but it completely failed.
ExplSyntaxOn
def@sortlist{}
newcommand{sortlist}[1]{
clist_set:Nn l_foo_clist {#1}
clist_sort:Nn l_foo_clist{
int_compare:nNnTF { ##1 } > { ##2 }
{ sort_return_swapped: }
{ sort_return_same: }
}
def@sortlist{l_foo_clist}
}
ExplSyntaxOff
Is there something like str_compare
to make a string comparison or can l3sort
actually only be used for numerical values?
Edit:
How to process a comma separated list? wasn't really helpful for me or rather I wasn't able to solve my problem thereby.
expl3 sorting comma-separated-list
Is there a simple way to sort a comma separated list alphabetically in LaTeX? I tried to write a macro (sortlist{World, Hello}
→ "Hello, World") using the l3sort
documentation example but it completely failed.
ExplSyntaxOn
def@sortlist{}
newcommand{sortlist}[1]{
clist_set:Nn l_foo_clist {#1}
clist_sort:Nn l_foo_clist{
int_compare:nNnTF { ##1 } > { ##2 }
{ sort_return_swapped: }
{ sort_return_same: }
}
def@sortlist{l_foo_clist}
}
ExplSyntaxOff
Is there something like str_compare
to make a string comparison or can l3sort
actually only be used for numerical values?
Edit:
How to process a comma separated list? wasn't really helpful for me or rather I wasn't able to solve my problem thereby.
expl3 sorting comma-separated-list
expl3 sorting comma-separated-list
edited 7 mins ago
tambre
1668
1668
asked Oct 11 '16 at 11:23
John
585
585
3
Welcome to TeX.SX! Knowing a bit more about your failed attempt and the kind of data you need to sort would be helpful.
– egreg
Oct 11 '16 at 11:30
1
Sorting strings of ASCII characters is feasible (although non yet supported byexpl3
); it would become much more complicated if words with accents and so on are involved.
– egreg
Oct 11 '16 at 12:37
add a comment |
3
Welcome to TeX.SX! Knowing a bit more about your failed attempt and the kind of data you need to sort would be helpful.
– egreg
Oct 11 '16 at 11:30
1
Sorting strings of ASCII characters is feasible (although non yet supported byexpl3
); it would become much more complicated if words with accents and so on are involved.
– egreg
Oct 11 '16 at 12:37
3
3
Welcome to TeX.SX! Knowing a bit more about your failed attempt and the kind of data you need to sort would be helpful.
– egreg
Oct 11 '16 at 11:30
Welcome to TeX.SX! Knowing a bit more about your failed attempt and the kind of data you need to sort would be helpful.
– egreg
Oct 11 '16 at 11:30
1
1
Sorting strings of ASCII characters is feasible (although non yet supported by
expl3
); it would become much more complicated if words with accents and so on are involved.– egreg
Oct 11 '16 at 12:37
Sorting strings of ASCII characters is feasible (although non yet supported by
expl3
); it would become much more complicated if words with accents and so on are involved.– egreg
Oct 11 '16 at 12:37
add a comment |
4 Answers
4
active
oldest
votes
This seems to work, with no packages. EDITED to solve the upper/lower-case problem.
EDIT: Resolved problem when a comparison ran out of letters prior to resolving the order, for example, wash, washer
.
See ADDENDUM for handling (after a fashion) diacritics.
documentclass{article}
deflistterminator{;}
makeatletter
newcommandalphabubblesort[1]{defpresorted{}defsortedlist{}%
sortlist#1,listterminator,relax}
defsortlist#1#2,#3#4,#5relax{%
iflistterminator#3#4relax%
edefsortedlist{sortedlist#1#2}%
else
ifnumthelccode`#1<thelccode`#3relax%
edefsortedlist{sortedlistpresorted#1#2, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else%
ifnum`#1=`#3relax%
ifxrelax#2relax%
edefsortedlist{sortedlistpresorted#1#2, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else%
ifxrelax#4relax%
edefsortedlist{sortedlistpresorted#3#4, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#1#2}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else
g@addto@macropresorted{#1}%
sortlist#2,#4,#5relax%
fi%
fi%
else%
lettmpsortedlist%
defsortedlist{}%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
expandafterdefexpandaftersvsecondexpandafter{presorted#1#2}%
defpresorted{}%
expandafterexpandafterexpandafterexpandafterexpandafter%
expandafterexpandaftersortlistexpandafterexpandafter%
expandaftertmpexpandaftersvfirstexpandafter,svsecond,#5relax%
fi%
fi%
fi%
}
makeatother
begin{document}
alphabubblesort{book, boot, boat,toad,attic,wish,wash,wasn't,Cat ,Xylophone}
sortedlistpar
alphabubblesort{book, washer, boot, boat,toad,attic,wish,wash,wasn't,Cat ,Xylophone}
sortedlistpar
end{document}
ADDENDUM
Here's a version that can handle diacritics, in the sense that they do not break the algorithm. This was accomplished by changing the edef
s in the above algorithm to appropriately expanded def
s.
However, diacritics here will always precede all non-diacritic letters in the sort. While maybe not the ideal behavior, it may still be useful.
documentclass{article}
deflistterminator{;}
makeatletter
newcommandalphabubblesort[1]{defpresorted{}defsortedlist{}%
sortlist#1,listterminator,relax}
defsortlist#1#2,#3#4,#5relax{%
iflistterminator#3#4relax%
expandafterdefexpandaftersortedlistexpandafter{sortedlist#1#2}%
else
ifnumthelccode`#1<thelccode`#3relax%
expandafterexpandafterexpandafterdefexpandafterexpandafter%
expandaftersortedlistexpandafterexpandafterexpandafter{%
expandaftersortedlistpresorted#1#2, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else%
ifnum`#1=`#3relax%
ifxrelax#2relax%
expandafterexpandafterexpandafterdefexpandafterexpandafter%
expandaftersortedlistexpandafterexpandafterexpandafter{%
expandaftersortedlistpresorted#1#2, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else%
ifxrelax#4relax%
expandafterexpandafterexpandafterdefexpandafterexpandafter%
expandaftersortedlistexpandafterexpandafterexpandafter{%
expandaftersortedlistpresorted#3#4, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#1#2}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else
g@addto@macropresorted{#1}%
sortlist#2,#4,#5relax%
fi%
fi%
else%
lettmpsortedlist%
defsortedlist{}%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
expandafterdefexpandaftersvsecondexpandafter{presorted#1#2}%
defpresorted{}%
expandafterexpandafterexpandafterexpandafterexpandafter%
expandafterexpandaftersortlistexpandafterexpandafter%
expandaftertmpexpandaftersvfirstexpandafter,svsecond,#5relax%
fi%
fi%
fi%
}
makeatother
begin{document}
alphabubblesort{book, washer, w"asher, boot, boat,toad,attic,wish,wash,wasn't,
Cat, Xylophone, w"ash, edifice, 'edifice, w"asherei}
sortedlistpar
end{document}
The algorithm was based on my bubblesort
macro here: Using LaTeX to compact a list of numbers
4
No stackengine: boo hiss. ;-)
– JPi
Oct 11 '16 at 13:40
2
@JPi I know... it hurts, doesn't it.
– Steven B. Segletes
Oct 11 '16 at 14:29
add a comment |
How about Lua?
defsortlist#1{%
directlua{%
local t = { #1 }
table.sort(t)
tex.sprint(table.concat(t,", "))
}%
}
sortlist{"World", "Hello"}
bye
Addendum: One of the really useful advantages of this approach is that it is fully expandable, meaning that after
edefx{sortlist{"World", "Hello"}}
the macro x
will contain the sorted list.
When using ConTeXt MKIV you can use the internal settings parser to convert a comma separated list to a Lua table. This has the advantage that you don't need to handle quotes yourself. It also respects grouping with commas inside.
defsortlist#1{%
ctxlua{%
local t = utilities.parsers.settings_to_array("luaescapestring{#1}")
table.sort(t)
tex.sprint(table.concat(t,", "))
}%
}
starttext
sortlist{World, Hello, {Entry, with, commas}, "Quotes"}
stoptext
We (theTeX
community) should definitely start a list of "generic" lua modules / functions, written forcontext
, that could be easily used with other formats (à laluaotfload
) with a wrapper. No need to reinvent the wheel.
– cjorssen
Oct 12 '16 at 8:34
add a comment |
You can safely compare strings consisting of ASCII characters; words with accented characters will not work.
documentclass{article}
usepackage{expl3,l3sort,xparse}
ExplSyntaxOn
prg_new_conditional:Nnn john_string_if_before:nn { p,T,F,TF }
{% I hope the LaTeX3 police won't catch me
int_compare:nTF { pdftex_strcmp:D { #1 } { #2 } < 0 }
{
prg_return_true:
}
{
prg_return_false:
}
}
NewDocumentCommand{sortlist}{smm}
{
IfBooleanTF{#1}
{
clist_set:No l__john_sortlist_data_clist { #2 }
}
{
clist_set:Nn l__john_sortlist_data_clist { #2 }
}
john_sortlist:N l__john_sortlist_data_clist
clist_set_eq:NN #3 l__john_sortlist_data_clist
}
clist_new:N l__john_sortlist_data_clist
cs_new_protected:Nn john_sortlist:N
{
clist_sort:Nn #1
{
john_string_if_before:nnTF { ##1 } { ##2 }
{
sort_ordered:
}
{
sort_reversed:
}
}
}
ExplSyntaxOff
begin{document}
sortlist{World,Hello}{mylistA}
mylistA
newcommand{mylistB}{duck,cat,dog}
sortlist*{mylistB}{mylistC}
mylistB ${}to{}$mylistC
end{document}
If you want that the comparison is case insensitive, change the definition of john_sortlist:N
into
cs_new_protected:Nn john_sortlist:N
{
clist_sort:Nn #1
{
john_string_if_before:nnTF { str_lower_case:n {##1} } { str_lower_case:n {##2} }
{
sort_ordered:
}
{
sort_reversed:
}
}
}
add a comment |
You can try this
This is taken over from https://tex.stackexchange.com/a/273084/4686 (code 5)
% ------------------------------------------------------------------
% Expandable routine to sort strings, based on a QuickSort algorithm
% and using pdfstrcmp.
% ------------------------------------------------------------------
% USAGE
% -----
% if using XeTeX:
% edefmysortedlist {QSfull{mylist}}, or explicit QSfull {foo, bar, zoo}
% if using PDFLaTeX: (and inputenc for accented letters)
% begingroup
% subdueutfviiienc
% globaledefmysortedlist {QSfull{mylist}}
% endgroup
documentclass{article}
ifdefinedXeTeXinterchartoks
letpdfstrcmpstrcmp
usepackage{fontspec}
else
usepackage[T1]{fontenc}
usepackage[utf8]{inputenc}% for PDFLaTeX
makeatletter
% this subdueutfviiienc allows é, à, etc... to survive as is to edef's.
newcommand*subdueutfviiienc {% to be used in a group
count@="C2
loop
lccode`~count@
lowercase{def~####1{noexpand~string####1}}%
ifnumcount@<"E0
advancecount@@ne
repeat
loop
lccode`~count@
lowercase{def~####1####2{noexpand~string####1string####2}}%
ifnumcount@<"F0
advancecount@@ne
repeat
loop
lccode`~count@
lowercase{def~####1####2####3{noexpand~string####1string####2string####3}}%
ifnumcount@<"F4
advancecount@@ne
repeat
}makeatother
% (if inputenc is used with 8bit encoding another approach would be needed)
fi
% CODE TAKEN FROM https://tex.stackexchange.com/a/273084/4686 (code 5)
% -------------------------------------------------------------------
makeatletter
longdefxintdothis #1#2xintorthat #3{fi #1}%
letxintorthat @firstofone
%
% use some (improbable) tokens as delimiters
catcode`! 3
catcode`? 3
catcode`; 3
%
% first we check if empty list (else qsfull@finish will not find a comma)
% we apply f-expansion to the argument to allow it to be a macro.
%
defQSfull #1{expandafterqsfull@aromannumeral-`0#1,!,?}%
%
% first check if input has only blanks, or is empty
defqsfull@a #1{ifx,#1xintdothisqsfull@afi
ifx!#1xintdothisqsfull@abortfi
xintorthat{qsfull@start #1}}%
defqsfull@abort #1?{}%
%
defqsfull@start {expandafterqsfull@finishromannumeral0qsfull@b,}%
defqsfull@finish ,#1{#1}% remove initial ,<space>
defqsfull@b ,#1#2,#3{ifx?#3xintdothisqsfull@emptylistfi
ifx!#3xintdothisqsfull@singletonfi
xintorthat qsfull@separate@a {}{}#1#2;#3}%
defqsfull@emptylist #1?{}%
defqsfull@singleton #1#2#3;!,?{, #3}%
%
defqsfull@separate@a #1#2#3;#4#5,%
% first pass, remove blanks in passing.
% no need to be extra efficient for that.
{%
ifx,#4expandafterqsfull@valueisblankfi
ifx!#4expandafterqsfull@separate@donefi
if1pdfstrcmp{#4#5}{#3}%
expandafterqsfull@separate@a@appendtogreater
elseexpandafterqsfull@separate@a@appendtosmaller
fi
#4#5?{#1}{#2}#3;%
}%
defqsfull@valueisblank ifx#1fi,#2?#3#4#5;{qsfull@separate@a {#3}{#4}#5;#2,}%
defqsfull@separate@a@appendtogreater #1?#2{qsfull@separate@a {#2, #1}}%
%
defqsfull@separate@a@appendtosmaller #1?#2#3{qsfull@separate@a {#2}{#3, #1}}%
%
defqsfull@separate@doneif#1fi #2?#3#4#5;?%
{%
qsfull@c #4,!,?, #5qsfull@c #3,!,?%
}%
% Now that the first pass is done, there are no more blank items.
% In particular here.
defqsfull@c ,#1#2,#3{ifx?#3xintdothisqsfull@emptylistfi
ifx!#3xintdothisqsfull@singletonfi
xintorthat qsfull@separate {}{}#1#2;#3}%
%
defqsfull@separate #1#2#3;#4#5,% blanks have already been filtered out.
{%
ifx!#4expandafterqsfull@separate@donefi
if1pdfstrcmp{#4#5}{#3}%
expandafterqsfull@separate@a@appendtogreater
elseexpandafterqsfull@separate@a@appendtosmaller
fi
#4#5?{#1}{#2}#3;%
}%
defqsfull@separate@appendtogreater #1?#2{qsfull@separate {#2, #1}}%
defqsfull@separate@appendtosmaller #1?#2#3{qsfull@separate {#2}{#3, #1}}%
%
%
catcode`! 12
catcode`? 12
catcode`; 12
makeatother
begin{document}
defmylist{book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't,
Cat, Xylophone, wäsh, edifice, édifice, wäsherei}
% use either a macro mylist or explicit list as QSfull argument.
ifdefinedXeTeXinterchartoks
edefmysortedlist{QSfull{mylist}}
else
{subdueutfviiiencglobaledefmysortedlist{QSfull{mylist}}}%
fi
mylistpar
medskip
becomes (notice how whitespaces are normalized in the process):
medskip
mysortedlist
medskip
For some reason due to the comparison being done by verb|pdfstrcmp| the é
comes after a-z.
% check
typeout{meaningmylist}
typeout{meaningmysortedlist}
end{document}
Here in the log output, with PDFLaTeX:
macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xyl
ophone, wäsh, edifice, édifice, wäsherei
macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, w
asn't, wish, wäsh, wäsher, wäsherei, édifice
and using XeLaTeX (which does not cut lines the same way):
macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xylo
phone, wäsh, edifice, édifice, wäsherei
macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, w
asn't, wish, wäsh, wäsher, wäsherei, édifice
The console output (again XeLaTeX) is still different, lines not cut:
macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xylophone, wäsh, edifice, édifice, wäsherei
macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, wasn't, wish, wäsh, wäsher, wäsherei, édifice
The complications with inputenc-made active characters are due to the fact we neededef
to get complete expansion. But the coding could be modified to achieve complete expansion under repeated expansion of first token. In fact code 3 et 4 of tex.stackexchange.com/a/273084/4686 do that. Then no need forsubdueutfviiienc
.
– jfbu
Oct 12 '16 at 9:51
add a comment |
Your Answer
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "85"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f333646%2fsorting-a-comma-separated-list-with-latex%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
This seems to work, with no packages. EDITED to solve the upper/lower-case problem.
EDIT: Resolved problem when a comparison ran out of letters prior to resolving the order, for example, wash, washer
.
See ADDENDUM for handling (after a fashion) diacritics.
documentclass{article}
deflistterminator{;}
makeatletter
newcommandalphabubblesort[1]{defpresorted{}defsortedlist{}%
sortlist#1,listterminator,relax}
defsortlist#1#2,#3#4,#5relax{%
iflistterminator#3#4relax%
edefsortedlist{sortedlist#1#2}%
else
ifnumthelccode`#1<thelccode`#3relax%
edefsortedlist{sortedlistpresorted#1#2, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else%
ifnum`#1=`#3relax%
ifxrelax#2relax%
edefsortedlist{sortedlistpresorted#1#2, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else%
ifxrelax#4relax%
edefsortedlist{sortedlistpresorted#3#4, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#1#2}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else
g@addto@macropresorted{#1}%
sortlist#2,#4,#5relax%
fi%
fi%
else%
lettmpsortedlist%
defsortedlist{}%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
expandafterdefexpandaftersvsecondexpandafter{presorted#1#2}%
defpresorted{}%
expandafterexpandafterexpandafterexpandafterexpandafter%
expandafterexpandaftersortlistexpandafterexpandafter%
expandaftertmpexpandaftersvfirstexpandafter,svsecond,#5relax%
fi%
fi%
fi%
}
makeatother
begin{document}
alphabubblesort{book, boot, boat,toad,attic,wish,wash,wasn't,Cat ,Xylophone}
sortedlistpar
alphabubblesort{book, washer, boot, boat,toad,attic,wish,wash,wasn't,Cat ,Xylophone}
sortedlistpar
end{document}
ADDENDUM
Here's a version that can handle diacritics, in the sense that they do not break the algorithm. This was accomplished by changing the edef
s in the above algorithm to appropriately expanded def
s.
However, diacritics here will always precede all non-diacritic letters in the sort. While maybe not the ideal behavior, it may still be useful.
documentclass{article}
deflistterminator{;}
makeatletter
newcommandalphabubblesort[1]{defpresorted{}defsortedlist{}%
sortlist#1,listterminator,relax}
defsortlist#1#2,#3#4,#5relax{%
iflistterminator#3#4relax%
expandafterdefexpandaftersortedlistexpandafter{sortedlist#1#2}%
else
ifnumthelccode`#1<thelccode`#3relax%
expandafterexpandafterexpandafterdefexpandafterexpandafter%
expandaftersortedlistexpandafterexpandafterexpandafter{%
expandaftersortedlistpresorted#1#2, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else%
ifnum`#1=`#3relax%
ifxrelax#2relax%
expandafterexpandafterexpandafterdefexpandafterexpandafter%
expandaftersortedlistexpandafterexpandafterexpandafter{%
expandaftersortedlistpresorted#1#2, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else%
ifxrelax#4relax%
expandafterexpandafterexpandafterdefexpandafterexpandafter%
expandaftersortedlistexpandafterexpandafterexpandafter{%
expandaftersortedlistpresorted#3#4, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#1#2}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else
g@addto@macropresorted{#1}%
sortlist#2,#4,#5relax%
fi%
fi%
else%
lettmpsortedlist%
defsortedlist{}%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
expandafterdefexpandaftersvsecondexpandafter{presorted#1#2}%
defpresorted{}%
expandafterexpandafterexpandafterexpandafterexpandafter%
expandafterexpandaftersortlistexpandafterexpandafter%
expandaftertmpexpandaftersvfirstexpandafter,svsecond,#5relax%
fi%
fi%
fi%
}
makeatother
begin{document}
alphabubblesort{book, washer, w"asher, boot, boat,toad,attic,wish,wash,wasn't,
Cat, Xylophone, w"ash, edifice, 'edifice, w"asherei}
sortedlistpar
end{document}
The algorithm was based on my bubblesort
macro here: Using LaTeX to compact a list of numbers
4
No stackengine: boo hiss. ;-)
– JPi
Oct 11 '16 at 13:40
2
@JPi I know... it hurts, doesn't it.
– Steven B. Segletes
Oct 11 '16 at 14:29
add a comment |
This seems to work, with no packages. EDITED to solve the upper/lower-case problem.
EDIT: Resolved problem when a comparison ran out of letters prior to resolving the order, for example, wash, washer
.
See ADDENDUM for handling (after a fashion) diacritics.
documentclass{article}
deflistterminator{;}
makeatletter
newcommandalphabubblesort[1]{defpresorted{}defsortedlist{}%
sortlist#1,listterminator,relax}
defsortlist#1#2,#3#4,#5relax{%
iflistterminator#3#4relax%
edefsortedlist{sortedlist#1#2}%
else
ifnumthelccode`#1<thelccode`#3relax%
edefsortedlist{sortedlistpresorted#1#2, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else%
ifnum`#1=`#3relax%
ifxrelax#2relax%
edefsortedlist{sortedlistpresorted#1#2, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else%
ifxrelax#4relax%
edefsortedlist{sortedlistpresorted#3#4, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#1#2}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else
g@addto@macropresorted{#1}%
sortlist#2,#4,#5relax%
fi%
fi%
else%
lettmpsortedlist%
defsortedlist{}%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
expandafterdefexpandaftersvsecondexpandafter{presorted#1#2}%
defpresorted{}%
expandafterexpandafterexpandafterexpandafterexpandafter%
expandafterexpandaftersortlistexpandafterexpandafter%
expandaftertmpexpandaftersvfirstexpandafter,svsecond,#5relax%
fi%
fi%
fi%
}
makeatother
begin{document}
alphabubblesort{book, boot, boat,toad,attic,wish,wash,wasn't,Cat ,Xylophone}
sortedlistpar
alphabubblesort{book, washer, boot, boat,toad,attic,wish,wash,wasn't,Cat ,Xylophone}
sortedlistpar
end{document}
ADDENDUM
Here's a version that can handle diacritics, in the sense that they do not break the algorithm. This was accomplished by changing the edef
s in the above algorithm to appropriately expanded def
s.
However, diacritics here will always precede all non-diacritic letters in the sort. While maybe not the ideal behavior, it may still be useful.
documentclass{article}
deflistterminator{;}
makeatletter
newcommandalphabubblesort[1]{defpresorted{}defsortedlist{}%
sortlist#1,listterminator,relax}
defsortlist#1#2,#3#4,#5relax{%
iflistterminator#3#4relax%
expandafterdefexpandaftersortedlistexpandafter{sortedlist#1#2}%
else
ifnumthelccode`#1<thelccode`#3relax%
expandafterexpandafterexpandafterdefexpandafterexpandafter%
expandaftersortedlistexpandafterexpandafterexpandafter{%
expandaftersortedlistpresorted#1#2, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else%
ifnum`#1=`#3relax%
ifxrelax#2relax%
expandafterexpandafterexpandafterdefexpandafterexpandafter%
expandaftersortedlistexpandafterexpandafterexpandafter{%
expandaftersortedlistpresorted#1#2, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else%
ifxrelax#4relax%
expandafterexpandafterexpandafterdefexpandafterexpandafter%
expandaftersortedlistexpandafterexpandafterexpandafter{%
expandaftersortedlistpresorted#3#4, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#1#2}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else
g@addto@macropresorted{#1}%
sortlist#2,#4,#5relax%
fi%
fi%
else%
lettmpsortedlist%
defsortedlist{}%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
expandafterdefexpandaftersvsecondexpandafter{presorted#1#2}%
defpresorted{}%
expandafterexpandafterexpandafterexpandafterexpandafter%
expandafterexpandaftersortlistexpandafterexpandafter%
expandaftertmpexpandaftersvfirstexpandafter,svsecond,#5relax%
fi%
fi%
fi%
}
makeatother
begin{document}
alphabubblesort{book, washer, w"asher, boot, boat,toad,attic,wish,wash,wasn't,
Cat, Xylophone, w"ash, edifice, 'edifice, w"asherei}
sortedlistpar
end{document}
The algorithm was based on my bubblesort
macro here: Using LaTeX to compact a list of numbers
4
No stackengine: boo hiss. ;-)
– JPi
Oct 11 '16 at 13:40
2
@JPi I know... it hurts, doesn't it.
– Steven B. Segletes
Oct 11 '16 at 14:29
add a comment |
This seems to work, with no packages. EDITED to solve the upper/lower-case problem.
EDIT: Resolved problem when a comparison ran out of letters prior to resolving the order, for example, wash, washer
.
See ADDENDUM for handling (after a fashion) diacritics.
documentclass{article}
deflistterminator{;}
makeatletter
newcommandalphabubblesort[1]{defpresorted{}defsortedlist{}%
sortlist#1,listterminator,relax}
defsortlist#1#2,#3#4,#5relax{%
iflistterminator#3#4relax%
edefsortedlist{sortedlist#1#2}%
else
ifnumthelccode`#1<thelccode`#3relax%
edefsortedlist{sortedlistpresorted#1#2, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else%
ifnum`#1=`#3relax%
ifxrelax#2relax%
edefsortedlist{sortedlistpresorted#1#2, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else%
ifxrelax#4relax%
edefsortedlist{sortedlistpresorted#3#4, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#1#2}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else
g@addto@macropresorted{#1}%
sortlist#2,#4,#5relax%
fi%
fi%
else%
lettmpsortedlist%
defsortedlist{}%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
expandafterdefexpandaftersvsecondexpandafter{presorted#1#2}%
defpresorted{}%
expandafterexpandafterexpandafterexpandafterexpandafter%
expandafterexpandaftersortlistexpandafterexpandafter%
expandaftertmpexpandaftersvfirstexpandafter,svsecond,#5relax%
fi%
fi%
fi%
}
makeatother
begin{document}
alphabubblesort{book, boot, boat,toad,attic,wish,wash,wasn't,Cat ,Xylophone}
sortedlistpar
alphabubblesort{book, washer, boot, boat,toad,attic,wish,wash,wasn't,Cat ,Xylophone}
sortedlistpar
end{document}
ADDENDUM
Here's a version that can handle diacritics, in the sense that they do not break the algorithm. This was accomplished by changing the edef
s in the above algorithm to appropriately expanded def
s.
However, diacritics here will always precede all non-diacritic letters in the sort. While maybe not the ideal behavior, it may still be useful.
documentclass{article}
deflistterminator{;}
makeatletter
newcommandalphabubblesort[1]{defpresorted{}defsortedlist{}%
sortlist#1,listterminator,relax}
defsortlist#1#2,#3#4,#5relax{%
iflistterminator#3#4relax%
expandafterdefexpandaftersortedlistexpandafter{sortedlist#1#2}%
else
ifnumthelccode`#1<thelccode`#3relax%
expandafterexpandafterexpandafterdefexpandafterexpandafter%
expandaftersortedlistexpandafterexpandafterexpandafter{%
expandaftersortedlistpresorted#1#2, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else%
ifnum`#1=`#3relax%
ifxrelax#2relax%
expandafterexpandafterexpandafterdefexpandafterexpandafter%
expandaftersortedlistexpandafterexpandafterexpandafter{%
expandaftersortedlistpresorted#1#2, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else%
ifxrelax#4relax%
expandafterexpandafterexpandafterdefexpandafterexpandafter%
expandaftersortedlistexpandafterexpandafterexpandafter{%
expandaftersortedlistpresorted#3#4, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#1#2}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else
g@addto@macropresorted{#1}%
sortlist#2,#4,#5relax%
fi%
fi%
else%
lettmpsortedlist%
defsortedlist{}%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
expandafterdefexpandaftersvsecondexpandafter{presorted#1#2}%
defpresorted{}%
expandafterexpandafterexpandafterexpandafterexpandafter%
expandafterexpandaftersortlistexpandafterexpandafter%
expandaftertmpexpandaftersvfirstexpandafter,svsecond,#5relax%
fi%
fi%
fi%
}
makeatother
begin{document}
alphabubblesort{book, washer, w"asher, boot, boat,toad,attic,wish,wash,wasn't,
Cat, Xylophone, w"ash, edifice, 'edifice, w"asherei}
sortedlistpar
end{document}
The algorithm was based on my bubblesort
macro here: Using LaTeX to compact a list of numbers
This seems to work, with no packages. EDITED to solve the upper/lower-case problem.
EDIT: Resolved problem when a comparison ran out of letters prior to resolving the order, for example, wash, washer
.
See ADDENDUM for handling (after a fashion) diacritics.
documentclass{article}
deflistterminator{;}
makeatletter
newcommandalphabubblesort[1]{defpresorted{}defsortedlist{}%
sortlist#1,listterminator,relax}
defsortlist#1#2,#3#4,#5relax{%
iflistterminator#3#4relax%
edefsortedlist{sortedlist#1#2}%
else
ifnumthelccode`#1<thelccode`#3relax%
edefsortedlist{sortedlistpresorted#1#2, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else%
ifnum`#1=`#3relax%
ifxrelax#2relax%
edefsortedlist{sortedlistpresorted#1#2, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else%
ifxrelax#4relax%
edefsortedlist{sortedlistpresorted#3#4, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#1#2}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else
g@addto@macropresorted{#1}%
sortlist#2,#4,#5relax%
fi%
fi%
else%
lettmpsortedlist%
defsortedlist{}%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
expandafterdefexpandaftersvsecondexpandafter{presorted#1#2}%
defpresorted{}%
expandafterexpandafterexpandafterexpandafterexpandafter%
expandafterexpandaftersortlistexpandafterexpandafter%
expandaftertmpexpandaftersvfirstexpandafter,svsecond,#5relax%
fi%
fi%
fi%
}
makeatother
begin{document}
alphabubblesort{book, boot, boat,toad,attic,wish,wash,wasn't,Cat ,Xylophone}
sortedlistpar
alphabubblesort{book, washer, boot, boat,toad,attic,wish,wash,wasn't,Cat ,Xylophone}
sortedlistpar
end{document}
ADDENDUM
Here's a version that can handle diacritics, in the sense that they do not break the algorithm. This was accomplished by changing the edef
s in the above algorithm to appropriately expanded def
s.
However, diacritics here will always precede all non-diacritic letters in the sort. While maybe not the ideal behavior, it may still be useful.
documentclass{article}
deflistterminator{;}
makeatletter
newcommandalphabubblesort[1]{defpresorted{}defsortedlist{}%
sortlist#1,listterminator,relax}
defsortlist#1#2,#3#4,#5relax{%
iflistterminator#3#4relax%
expandafterdefexpandaftersortedlistexpandafter{sortedlist#1#2}%
else
ifnumthelccode`#1<thelccode`#3relax%
expandafterexpandafterexpandafterdefexpandafterexpandafter%
expandaftersortedlistexpandafterexpandafterexpandafter{%
expandaftersortedlistpresorted#1#2, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else%
ifnum`#1=`#3relax%
ifxrelax#2relax%
expandafterexpandafterexpandafterdefexpandafterexpandafter%
expandaftersortedlistexpandafterexpandafterexpandafter{%
expandaftersortedlistpresorted#1#2, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else%
ifxrelax#4relax%
expandafterexpandafterexpandafterdefexpandafterexpandafter%
expandaftersortedlistexpandafterexpandafterexpandafter{%
expandaftersortedlistpresorted#3#4, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#1#2}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else
g@addto@macropresorted{#1}%
sortlist#2,#4,#5relax%
fi%
fi%
else%
lettmpsortedlist%
defsortedlist{}%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
expandafterdefexpandaftersvsecondexpandafter{presorted#1#2}%
defpresorted{}%
expandafterexpandafterexpandafterexpandafterexpandafter%
expandafterexpandaftersortlistexpandafterexpandafter%
expandaftertmpexpandaftersvfirstexpandafter,svsecond,#5relax%
fi%
fi%
fi%
}
makeatother
begin{document}
alphabubblesort{book, washer, w"asher, boot, boat,toad,attic,wish,wash,wasn't,
Cat, Xylophone, w"ash, edifice, 'edifice, w"asherei}
sortedlistpar
end{document}
The algorithm was based on my bubblesort
macro here: Using LaTeX to compact a list of numbers
edited Apr 13 '17 at 12:35
Community♦
1
1
answered Oct 11 '16 at 13:11
Steven B. Segletes
152k9193400
152k9193400
4
No stackengine: boo hiss. ;-)
– JPi
Oct 11 '16 at 13:40
2
@JPi I know... it hurts, doesn't it.
– Steven B. Segletes
Oct 11 '16 at 14:29
add a comment |
4
No stackengine: boo hiss. ;-)
– JPi
Oct 11 '16 at 13:40
2
@JPi I know... it hurts, doesn't it.
– Steven B. Segletes
Oct 11 '16 at 14:29
4
4
No stackengine: boo hiss. ;-)
– JPi
Oct 11 '16 at 13:40
No stackengine: boo hiss. ;-)
– JPi
Oct 11 '16 at 13:40
2
2
@JPi I know... it hurts, doesn't it.
– Steven B. Segletes
Oct 11 '16 at 14:29
@JPi I know... it hurts, doesn't it.
– Steven B. Segletes
Oct 11 '16 at 14:29
add a comment |
How about Lua?
defsortlist#1{%
directlua{%
local t = { #1 }
table.sort(t)
tex.sprint(table.concat(t,", "))
}%
}
sortlist{"World", "Hello"}
bye
Addendum: One of the really useful advantages of this approach is that it is fully expandable, meaning that after
edefx{sortlist{"World", "Hello"}}
the macro x
will contain the sorted list.
When using ConTeXt MKIV you can use the internal settings parser to convert a comma separated list to a Lua table. This has the advantage that you don't need to handle quotes yourself. It also respects grouping with commas inside.
defsortlist#1{%
ctxlua{%
local t = utilities.parsers.settings_to_array("luaescapestring{#1}")
table.sort(t)
tex.sprint(table.concat(t,", "))
}%
}
starttext
sortlist{World, Hello, {Entry, with, commas}, "Quotes"}
stoptext
We (theTeX
community) should definitely start a list of "generic" lua modules / functions, written forcontext
, that could be easily used with other formats (à laluaotfload
) with a wrapper. No need to reinvent the wheel.
– cjorssen
Oct 12 '16 at 8:34
add a comment |
How about Lua?
defsortlist#1{%
directlua{%
local t = { #1 }
table.sort(t)
tex.sprint(table.concat(t,", "))
}%
}
sortlist{"World", "Hello"}
bye
Addendum: One of the really useful advantages of this approach is that it is fully expandable, meaning that after
edefx{sortlist{"World", "Hello"}}
the macro x
will contain the sorted list.
When using ConTeXt MKIV you can use the internal settings parser to convert a comma separated list to a Lua table. This has the advantage that you don't need to handle quotes yourself. It also respects grouping with commas inside.
defsortlist#1{%
ctxlua{%
local t = utilities.parsers.settings_to_array("luaescapestring{#1}")
table.sort(t)
tex.sprint(table.concat(t,", "))
}%
}
starttext
sortlist{World, Hello, {Entry, with, commas}, "Quotes"}
stoptext
We (theTeX
community) should definitely start a list of "generic" lua modules / functions, written forcontext
, that could be easily used with other formats (à laluaotfload
) with a wrapper. No need to reinvent the wheel.
– cjorssen
Oct 12 '16 at 8:34
add a comment |
How about Lua?
defsortlist#1{%
directlua{%
local t = { #1 }
table.sort(t)
tex.sprint(table.concat(t,", "))
}%
}
sortlist{"World", "Hello"}
bye
Addendum: One of the really useful advantages of this approach is that it is fully expandable, meaning that after
edefx{sortlist{"World", "Hello"}}
the macro x
will contain the sorted list.
When using ConTeXt MKIV you can use the internal settings parser to convert a comma separated list to a Lua table. This has the advantage that you don't need to handle quotes yourself. It also respects grouping with commas inside.
defsortlist#1{%
ctxlua{%
local t = utilities.parsers.settings_to_array("luaescapestring{#1}")
table.sort(t)
tex.sprint(table.concat(t,", "))
}%
}
starttext
sortlist{World, Hello, {Entry, with, commas}, "Quotes"}
stoptext
How about Lua?
defsortlist#1{%
directlua{%
local t = { #1 }
table.sort(t)
tex.sprint(table.concat(t,", "))
}%
}
sortlist{"World", "Hello"}
bye
Addendum: One of the really useful advantages of this approach is that it is fully expandable, meaning that after
edefx{sortlist{"World", "Hello"}}
the macro x
will contain the sorted list.
When using ConTeXt MKIV you can use the internal settings parser to convert a comma separated list to a Lua table. This has the advantage that you don't need to handle quotes yourself. It also respects grouping with commas inside.
defsortlist#1{%
ctxlua{%
local t = utilities.parsers.settings_to_array("luaescapestring{#1}")
table.sort(t)
tex.sprint(table.concat(t,", "))
}%
}
starttext
sortlist{World, Hello, {Entry, with, commas}, "Quotes"}
stoptext
edited Oct 12 '16 at 7:25
answered Oct 11 '16 at 12:28
Henri Menke
69.8k8155260
69.8k8155260
We (theTeX
community) should definitely start a list of "generic" lua modules / functions, written forcontext
, that could be easily used with other formats (à laluaotfload
) with a wrapper. No need to reinvent the wheel.
– cjorssen
Oct 12 '16 at 8:34
add a comment |
We (theTeX
community) should definitely start a list of "generic" lua modules / functions, written forcontext
, that could be easily used with other formats (à laluaotfload
) with a wrapper. No need to reinvent the wheel.
– cjorssen
Oct 12 '16 at 8:34
We (the
TeX
community) should definitely start a list of "generic" lua modules / functions, written for context
, that could be easily used with other formats (à la luaotfload
) with a wrapper. No need to reinvent the wheel.– cjorssen
Oct 12 '16 at 8:34
We (the
TeX
community) should definitely start a list of "generic" lua modules / functions, written for context
, that could be easily used with other formats (à la luaotfload
) with a wrapper. No need to reinvent the wheel.– cjorssen
Oct 12 '16 at 8:34
add a comment |
You can safely compare strings consisting of ASCII characters; words with accented characters will not work.
documentclass{article}
usepackage{expl3,l3sort,xparse}
ExplSyntaxOn
prg_new_conditional:Nnn john_string_if_before:nn { p,T,F,TF }
{% I hope the LaTeX3 police won't catch me
int_compare:nTF { pdftex_strcmp:D { #1 } { #2 } < 0 }
{
prg_return_true:
}
{
prg_return_false:
}
}
NewDocumentCommand{sortlist}{smm}
{
IfBooleanTF{#1}
{
clist_set:No l__john_sortlist_data_clist { #2 }
}
{
clist_set:Nn l__john_sortlist_data_clist { #2 }
}
john_sortlist:N l__john_sortlist_data_clist
clist_set_eq:NN #3 l__john_sortlist_data_clist
}
clist_new:N l__john_sortlist_data_clist
cs_new_protected:Nn john_sortlist:N
{
clist_sort:Nn #1
{
john_string_if_before:nnTF { ##1 } { ##2 }
{
sort_ordered:
}
{
sort_reversed:
}
}
}
ExplSyntaxOff
begin{document}
sortlist{World,Hello}{mylistA}
mylistA
newcommand{mylistB}{duck,cat,dog}
sortlist*{mylistB}{mylistC}
mylistB ${}to{}$mylistC
end{document}
If you want that the comparison is case insensitive, change the definition of john_sortlist:N
into
cs_new_protected:Nn john_sortlist:N
{
clist_sort:Nn #1
{
john_string_if_before:nnTF { str_lower_case:n {##1} } { str_lower_case:n {##2} }
{
sort_ordered:
}
{
sort_reversed:
}
}
}
add a comment |
You can safely compare strings consisting of ASCII characters; words with accented characters will not work.
documentclass{article}
usepackage{expl3,l3sort,xparse}
ExplSyntaxOn
prg_new_conditional:Nnn john_string_if_before:nn { p,T,F,TF }
{% I hope the LaTeX3 police won't catch me
int_compare:nTF { pdftex_strcmp:D { #1 } { #2 } < 0 }
{
prg_return_true:
}
{
prg_return_false:
}
}
NewDocumentCommand{sortlist}{smm}
{
IfBooleanTF{#1}
{
clist_set:No l__john_sortlist_data_clist { #2 }
}
{
clist_set:Nn l__john_sortlist_data_clist { #2 }
}
john_sortlist:N l__john_sortlist_data_clist
clist_set_eq:NN #3 l__john_sortlist_data_clist
}
clist_new:N l__john_sortlist_data_clist
cs_new_protected:Nn john_sortlist:N
{
clist_sort:Nn #1
{
john_string_if_before:nnTF { ##1 } { ##2 }
{
sort_ordered:
}
{
sort_reversed:
}
}
}
ExplSyntaxOff
begin{document}
sortlist{World,Hello}{mylistA}
mylistA
newcommand{mylistB}{duck,cat,dog}
sortlist*{mylistB}{mylistC}
mylistB ${}to{}$mylistC
end{document}
If you want that the comparison is case insensitive, change the definition of john_sortlist:N
into
cs_new_protected:Nn john_sortlist:N
{
clist_sort:Nn #1
{
john_string_if_before:nnTF { str_lower_case:n {##1} } { str_lower_case:n {##2} }
{
sort_ordered:
}
{
sort_reversed:
}
}
}
add a comment |
You can safely compare strings consisting of ASCII characters; words with accented characters will not work.
documentclass{article}
usepackage{expl3,l3sort,xparse}
ExplSyntaxOn
prg_new_conditional:Nnn john_string_if_before:nn { p,T,F,TF }
{% I hope the LaTeX3 police won't catch me
int_compare:nTF { pdftex_strcmp:D { #1 } { #2 } < 0 }
{
prg_return_true:
}
{
prg_return_false:
}
}
NewDocumentCommand{sortlist}{smm}
{
IfBooleanTF{#1}
{
clist_set:No l__john_sortlist_data_clist { #2 }
}
{
clist_set:Nn l__john_sortlist_data_clist { #2 }
}
john_sortlist:N l__john_sortlist_data_clist
clist_set_eq:NN #3 l__john_sortlist_data_clist
}
clist_new:N l__john_sortlist_data_clist
cs_new_protected:Nn john_sortlist:N
{
clist_sort:Nn #1
{
john_string_if_before:nnTF { ##1 } { ##2 }
{
sort_ordered:
}
{
sort_reversed:
}
}
}
ExplSyntaxOff
begin{document}
sortlist{World,Hello}{mylistA}
mylistA
newcommand{mylistB}{duck,cat,dog}
sortlist*{mylistB}{mylistC}
mylistB ${}to{}$mylistC
end{document}
If you want that the comparison is case insensitive, change the definition of john_sortlist:N
into
cs_new_protected:Nn john_sortlist:N
{
clist_sort:Nn #1
{
john_string_if_before:nnTF { str_lower_case:n {##1} } { str_lower_case:n {##2} }
{
sort_ordered:
}
{
sort_reversed:
}
}
}
You can safely compare strings consisting of ASCII characters; words with accented characters will not work.
documentclass{article}
usepackage{expl3,l3sort,xparse}
ExplSyntaxOn
prg_new_conditional:Nnn john_string_if_before:nn { p,T,F,TF }
{% I hope the LaTeX3 police won't catch me
int_compare:nTF { pdftex_strcmp:D { #1 } { #2 } < 0 }
{
prg_return_true:
}
{
prg_return_false:
}
}
NewDocumentCommand{sortlist}{smm}
{
IfBooleanTF{#1}
{
clist_set:No l__john_sortlist_data_clist { #2 }
}
{
clist_set:Nn l__john_sortlist_data_clist { #2 }
}
john_sortlist:N l__john_sortlist_data_clist
clist_set_eq:NN #3 l__john_sortlist_data_clist
}
clist_new:N l__john_sortlist_data_clist
cs_new_protected:Nn john_sortlist:N
{
clist_sort:Nn #1
{
john_string_if_before:nnTF { ##1 } { ##2 }
{
sort_ordered:
}
{
sort_reversed:
}
}
}
ExplSyntaxOff
begin{document}
sortlist{World,Hello}{mylistA}
mylistA
newcommand{mylistB}{duck,cat,dog}
sortlist*{mylistB}{mylistC}
mylistB ${}to{}$mylistC
end{document}
If you want that the comparison is case insensitive, change the definition of john_sortlist:N
into
cs_new_protected:Nn john_sortlist:N
{
clist_sort:Nn #1
{
john_string_if_before:nnTF { str_lower_case:n {##1} } { str_lower_case:n {##2} }
{
sort_ordered:
}
{
sort_reversed:
}
}
}
edited Oct 11 '16 at 13:49
answered Oct 11 '16 at 13:38
egreg
708k8618813163
708k8618813163
add a comment |
add a comment |
You can try this
This is taken over from https://tex.stackexchange.com/a/273084/4686 (code 5)
% ------------------------------------------------------------------
% Expandable routine to sort strings, based on a QuickSort algorithm
% and using pdfstrcmp.
% ------------------------------------------------------------------
% USAGE
% -----
% if using XeTeX:
% edefmysortedlist {QSfull{mylist}}, or explicit QSfull {foo, bar, zoo}
% if using PDFLaTeX: (and inputenc for accented letters)
% begingroup
% subdueutfviiienc
% globaledefmysortedlist {QSfull{mylist}}
% endgroup
documentclass{article}
ifdefinedXeTeXinterchartoks
letpdfstrcmpstrcmp
usepackage{fontspec}
else
usepackage[T1]{fontenc}
usepackage[utf8]{inputenc}% for PDFLaTeX
makeatletter
% this subdueutfviiienc allows é, à, etc... to survive as is to edef's.
newcommand*subdueutfviiienc {% to be used in a group
count@="C2
loop
lccode`~count@
lowercase{def~####1{noexpand~string####1}}%
ifnumcount@<"E0
advancecount@@ne
repeat
loop
lccode`~count@
lowercase{def~####1####2{noexpand~string####1string####2}}%
ifnumcount@<"F0
advancecount@@ne
repeat
loop
lccode`~count@
lowercase{def~####1####2####3{noexpand~string####1string####2string####3}}%
ifnumcount@<"F4
advancecount@@ne
repeat
}makeatother
% (if inputenc is used with 8bit encoding another approach would be needed)
fi
% CODE TAKEN FROM https://tex.stackexchange.com/a/273084/4686 (code 5)
% -------------------------------------------------------------------
makeatletter
longdefxintdothis #1#2xintorthat #3{fi #1}%
letxintorthat @firstofone
%
% use some (improbable) tokens as delimiters
catcode`! 3
catcode`? 3
catcode`; 3
%
% first we check if empty list (else qsfull@finish will not find a comma)
% we apply f-expansion to the argument to allow it to be a macro.
%
defQSfull #1{expandafterqsfull@aromannumeral-`0#1,!,?}%
%
% first check if input has only blanks, or is empty
defqsfull@a #1{ifx,#1xintdothisqsfull@afi
ifx!#1xintdothisqsfull@abortfi
xintorthat{qsfull@start #1}}%
defqsfull@abort #1?{}%
%
defqsfull@start {expandafterqsfull@finishromannumeral0qsfull@b,}%
defqsfull@finish ,#1{#1}% remove initial ,<space>
defqsfull@b ,#1#2,#3{ifx?#3xintdothisqsfull@emptylistfi
ifx!#3xintdothisqsfull@singletonfi
xintorthat qsfull@separate@a {}{}#1#2;#3}%
defqsfull@emptylist #1?{}%
defqsfull@singleton #1#2#3;!,?{, #3}%
%
defqsfull@separate@a #1#2#3;#4#5,%
% first pass, remove blanks in passing.
% no need to be extra efficient for that.
{%
ifx,#4expandafterqsfull@valueisblankfi
ifx!#4expandafterqsfull@separate@donefi
if1pdfstrcmp{#4#5}{#3}%
expandafterqsfull@separate@a@appendtogreater
elseexpandafterqsfull@separate@a@appendtosmaller
fi
#4#5?{#1}{#2}#3;%
}%
defqsfull@valueisblank ifx#1fi,#2?#3#4#5;{qsfull@separate@a {#3}{#4}#5;#2,}%
defqsfull@separate@a@appendtogreater #1?#2{qsfull@separate@a {#2, #1}}%
%
defqsfull@separate@a@appendtosmaller #1?#2#3{qsfull@separate@a {#2}{#3, #1}}%
%
defqsfull@separate@doneif#1fi #2?#3#4#5;?%
{%
qsfull@c #4,!,?, #5qsfull@c #3,!,?%
}%
% Now that the first pass is done, there are no more blank items.
% In particular here.
defqsfull@c ,#1#2,#3{ifx?#3xintdothisqsfull@emptylistfi
ifx!#3xintdothisqsfull@singletonfi
xintorthat qsfull@separate {}{}#1#2;#3}%
%
defqsfull@separate #1#2#3;#4#5,% blanks have already been filtered out.
{%
ifx!#4expandafterqsfull@separate@donefi
if1pdfstrcmp{#4#5}{#3}%
expandafterqsfull@separate@a@appendtogreater
elseexpandafterqsfull@separate@a@appendtosmaller
fi
#4#5?{#1}{#2}#3;%
}%
defqsfull@separate@appendtogreater #1?#2{qsfull@separate {#2, #1}}%
defqsfull@separate@appendtosmaller #1?#2#3{qsfull@separate {#2}{#3, #1}}%
%
%
catcode`! 12
catcode`? 12
catcode`; 12
makeatother
begin{document}
defmylist{book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't,
Cat, Xylophone, wäsh, edifice, édifice, wäsherei}
% use either a macro mylist or explicit list as QSfull argument.
ifdefinedXeTeXinterchartoks
edefmysortedlist{QSfull{mylist}}
else
{subdueutfviiiencglobaledefmysortedlist{QSfull{mylist}}}%
fi
mylistpar
medskip
becomes (notice how whitespaces are normalized in the process):
medskip
mysortedlist
medskip
For some reason due to the comparison being done by verb|pdfstrcmp| the é
comes after a-z.
% check
typeout{meaningmylist}
typeout{meaningmysortedlist}
end{document}
Here in the log output, with PDFLaTeX:
macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xyl
ophone, wäsh, edifice, édifice, wäsherei
macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, w
asn't, wish, wäsh, wäsher, wäsherei, édifice
and using XeLaTeX (which does not cut lines the same way):
macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xylo
phone, wäsh, edifice, édifice, wäsherei
macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, w
asn't, wish, wäsh, wäsher, wäsherei, édifice
The console output (again XeLaTeX) is still different, lines not cut:
macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xylophone, wäsh, edifice, édifice, wäsherei
macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, wasn't, wish, wäsh, wäsher, wäsherei, édifice
The complications with inputenc-made active characters are due to the fact we neededef
to get complete expansion. But the coding could be modified to achieve complete expansion under repeated expansion of first token. In fact code 3 et 4 of tex.stackexchange.com/a/273084/4686 do that. Then no need forsubdueutfviiienc
.
– jfbu
Oct 12 '16 at 9:51
add a comment |
You can try this
This is taken over from https://tex.stackexchange.com/a/273084/4686 (code 5)
% ------------------------------------------------------------------
% Expandable routine to sort strings, based on a QuickSort algorithm
% and using pdfstrcmp.
% ------------------------------------------------------------------
% USAGE
% -----
% if using XeTeX:
% edefmysortedlist {QSfull{mylist}}, or explicit QSfull {foo, bar, zoo}
% if using PDFLaTeX: (and inputenc for accented letters)
% begingroup
% subdueutfviiienc
% globaledefmysortedlist {QSfull{mylist}}
% endgroup
documentclass{article}
ifdefinedXeTeXinterchartoks
letpdfstrcmpstrcmp
usepackage{fontspec}
else
usepackage[T1]{fontenc}
usepackage[utf8]{inputenc}% for PDFLaTeX
makeatletter
% this subdueutfviiienc allows é, à, etc... to survive as is to edef's.
newcommand*subdueutfviiienc {% to be used in a group
count@="C2
loop
lccode`~count@
lowercase{def~####1{noexpand~string####1}}%
ifnumcount@<"E0
advancecount@@ne
repeat
loop
lccode`~count@
lowercase{def~####1####2{noexpand~string####1string####2}}%
ifnumcount@<"F0
advancecount@@ne
repeat
loop
lccode`~count@
lowercase{def~####1####2####3{noexpand~string####1string####2string####3}}%
ifnumcount@<"F4
advancecount@@ne
repeat
}makeatother
% (if inputenc is used with 8bit encoding another approach would be needed)
fi
% CODE TAKEN FROM https://tex.stackexchange.com/a/273084/4686 (code 5)
% -------------------------------------------------------------------
makeatletter
longdefxintdothis #1#2xintorthat #3{fi #1}%
letxintorthat @firstofone
%
% use some (improbable) tokens as delimiters
catcode`! 3
catcode`? 3
catcode`; 3
%
% first we check if empty list (else qsfull@finish will not find a comma)
% we apply f-expansion to the argument to allow it to be a macro.
%
defQSfull #1{expandafterqsfull@aromannumeral-`0#1,!,?}%
%
% first check if input has only blanks, or is empty
defqsfull@a #1{ifx,#1xintdothisqsfull@afi
ifx!#1xintdothisqsfull@abortfi
xintorthat{qsfull@start #1}}%
defqsfull@abort #1?{}%
%
defqsfull@start {expandafterqsfull@finishromannumeral0qsfull@b,}%
defqsfull@finish ,#1{#1}% remove initial ,<space>
defqsfull@b ,#1#2,#3{ifx?#3xintdothisqsfull@emptylistfi
ifx!#3xintdothisqsfull@singletonfi
xintorthat qsfull@separate@a {}{}#1#2;#3}%
defqsfull@emptylist #1?{}%
defqsfull@singleton #1#2#3;!,?{, #3}%
%
defqsfull@separate@a #1#2#3;#4#5,%
% first pass, remove blanks in passing.
% no need to be extra efficient for that.
{%
ifx,#4expandafterqsfull@valueisblankfi
ifx!#4expandafterqsfull@separate@donefi
if1pdfstrcmp{#4#5}{#3}%
expandafterqsfull@separate@a@appendtogreater
elseexpandafterqsfull@separate@a@appendtosmaller
fi
#4#5?{#1}{#2}#3;%
}%
defqsfull@valueisblank ifx#1fi,#2?#3#4#5;{qsfull@separate@a {#3}{#4}#5;#2,}%
defqsfull@separate@a@appendtogreater #1?#2{qsfull@separate@a {#2, #1}}%
%
defqsfull@separate@a@appendtosmaller #1?#2#3{qsfull@separate@a {#2}{#3, #1}}%
%
defqsfull@separate@doneif#1fi #2?#3#4#5;?%
{%
qsfull@c #4,!,?, #5qsfull@c #3,!,?%
}%
% Now that the first pass is done, there are no more blank items.
% In particular here.
defqsfull@c ,#1#2,#3{ifx?#3xintdothisqsfull@emptylistfi
ifx!#3xintdothisqsfull@singletonfi
xintorthat qsfull@separate {}{}#1#2;#3}%
%
defqsfull@separate #1#2#3;#4#5,% blanks have already been filtered out.
{%
ifx!#4expandafterqsfull@separate@donefi
if1pdfstrcmp{#4#5}{#3}%
expandafterqsfull@separate@a@appendtogreater
elseexpandafterqsfull@separate@a@appendtosmaller
fi
#4#5?{#1}{#2}#3;%
}%
defqsfull@separate@appendtogreater #1?#2{qsfull@separate {#2, #1}}%
defqsfull@separate@appendtosmaller #1?#2#3{qsfull@separate {#2}{#3, #1}}%
%
%
catcode`! 12
catcode`? 12
catcode`; 12
makeatother
begin{document}
defmylist{book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't,
Cat, Xylophone, wäsh, edifice, édifice, wäsherei}
% use either a macro mylist or explicit list as QSfull argument.
ifdefinedXeTeXinterchartoks
edefmysortedlist{QSfull{mylist}}
else
{subdueutfviiiencglobaledefmysortedlist{QSfull{mylist}}}%
fi
mylistpar
medskip
becomes (notice how whitespaces are normalized in the process):
medskip
mysortedlist
medskip
For some reason due to the comparison being done by verb|pdfstrcmp| the é
comes after a-z.
% check
typeout{meaningmylist}
typeout{meaningmysortedlist}
end{document}
Here in the log output, with PDFLaTeX:
macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xyl
ophone, wäsh, edifice, édifice, wäsherei
macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, w
asn't, wish, wäsh, wäsher, wäsherei, édifice
and using XeLaTeX (which does not cut lines the same way):
macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xylo
phone, wäsh, edifice, édifice, wäsherei
macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, w
asn't, wish, wäsh, wäsher, wäsherei, édifice
The console output (again XeLaTeX) is still different, lines not cut:
macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xylophone, wäsh, edifice, édifice, wäsherei
macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, wasn't, wish, wäsh, wäsher, wäsherei, édifice
The complications with inputenc-made active characters are due to the fact we neededef
to get complete expansion. But the coding could be modified to achieve complete expansion under repeated expansion of first token. In fact code 3 et 4 of tex.stackexchange.com/a/273084/4686 do that. Then no need forsubdueutfviiienc
.
– jfbu
Oct 12 '16 at 9:51
add a comment |
You can try this
This is taken over from https://tex.stackexchange.com/a/273084/4686 (code 5)
% ------------------------------------------------------------------
% Expandable routine to sort strings, based on a QuickSort algorithm
% and using pdfstrcmp.
% ------------------------------------------------------------------
% USAGE
% -----
% if using XeTeX:
% edefmysortedlist {QSfull{mylist}}, or explicit QSfull {foo, bar, zoo}
% if using PDFLaTeX: (and inputenc for accented letters)
% begingroup
% subdueutfviiienc
% globaledefmysortedlist {QSfull{mylist}}
% endgroup
documentclass{article}
ifdefinedXeTeXinterchartoks
letpdfstrcmpstrcmp
usepackage{fontspec}
else
usepackage[T1]{fontenc}
usepackage[utf8]{inputenc}% for PDFLaTeX
makeatletter
% this subdueutfviiienc allows é, à, etc... to survive as is to edef's.
newcommand*subdueutfviiienc {% to be used in a group
count@="C2
loop
lccode`~count@
lowercase{def~####1{noexpand~string####1}}%
ifnumcount@<"E0
advancecount@@ne
repeat
loop
lccode`~count@
lowercase{def~####1####2{noexpand~string####1string####2}}%
ifnumcount@<"F0
advancecount@@ne
repeat
loop
lccode`~count@
lowercase{def~####1####2####3{noexpand~string####1string####2string####3}}%
ifnumcount@<"F4
advancecount@@ne
repeat
}makeatother
% (if inputenc is used with 8bit encoding another approach would be needed)
fi
% CODE TAKEN FROM https://tex.stackexchange.com/a/273084/4686 (code 5)
% -------------------------------------------------------------------
makeatletter
longdefxintdothis #1#2xintorthat #3{fi #1}%
letxintorthat @firstofone
%
% use some (improbable) tokens as delimiters
catcode`! 3
catcode`? 3
catcode`; 3
%
% first we check if empty list (else qsfull@finish will not find a comma)
% we apply f-expansion to the argument to allow it to be a macro.
%
defQSfull #1{expandafterqsfull@aromannumeral-`0#1,!,?}%
%
% first check if input has only blanks, or is empty
defqsfull@a #1{ifx,#1xintdothisqsfull@afi
ifx!#1xintdothisqsfull@abortfi
xintorthat{qsfull@start #1}}%
defqsfull@abort #1?{}%
%
defqsfull@start {expandafterqsfull@finishromannumeral0qsfull@b,}%
defqsfull@finish ,#1{#1}% remove initial ,<space>
defqsfull@b ,#1#2,#3{ifx?#3xintdothisqsfull@emptylistfi
ifx!#3xintdothisqsfull@singletonfi
xintorthat qsfull@separate@a {}{}#1#2;#3}%
defqsfull@emptylist #1?{}%
defqsfull@singleton #1#2#3;!,?{, #3}%
%
defqsfull@separate@a #1#2#3;#4#5,%
% first pass, remove blanks in passing.
% no need to be extra efficient for that.
{%
ifx,#4expandafterqsfull@valueisblankfi
ifx!#4expandafterqsfull@separate@donefi
if1pdfstrcmp{#4#5}{#3}%
expandafterqsfull@separate@a@appendtogreater
elseexpandafterqsfull@separate@a@appendtosmaller
fi
#4#5?{#1}{#2}#3;%
}%
defqsfull@valueisblank ifx#1fi,#2?#3#4#5;{qsfull@separate@a {#3}{#4}#5;#2,}%
defqsfull@separate@a@appendtogreater #1?#2{qsfull@separate@a {#2, #1}}%
%
defqsfull@separate@a@appendtosmaller #1?#2#3{qsfull@separate@a {#2}{#3, #1}}%
%
defqsfull@separate@doneif#1fi #2?#3#4#5;?%
{%
qsfull@c #4,!,?, #5qsfull@c #3,!,?%
}%
% Now that the first pass is done, there are no more blank items.
% In particular here.
defqsfull@c ,#1#2,#3{ifx?#3xintdothisqsfull@emptylistfi
ifx!#3xintdothisqsfull@singletonfi
xintorthat qsfull@separate {}{}#1#2;#3}%
%
defqsfull@separate #1#2#3;#4#5,% blanks have already been filtered out.
{%
ifx!#4expandafterqsfull@separate@donefi
if1pdfstrcmp{#4#5}{#3}%
expandafterqsfull@separate@a@appendtogreater
elseexpandafterqsfull@separate@a@appendtosmaller
fi
#4#5?{#1}{#2}#3;%
}%
defqsfull@separate@appendtogreater #1?#2{qsfull@separate {#2, #1}}%
defqsfull@separate@appendtosmaller #1?#2#3{qsfull@separate {#2}{#3, #1}}%
%
%
catcode`! 12
catcode`? 12
catcode`; 12
makeatother
begin{document}
defmylist{book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't,
Cat, Xylophone, wäsh, edifice, édifice, wäsherei}
% use either a macro mylist or explicit list as QSfull argument.
ifdefinedXeTeXinterchartoks
edefmysortedlist{QSfull{mylist}}
else
{subdueutfviiiencglobaledefmysortedlist{QSfull{mylist}}}%
fi
mylistpar
medskip
becomes (notice how whitespaces are normalized in the process):
medskip
mysortedlist
medskip
For some reason due to the comparison being done by verb|pdfstrcmp| the é
comes after a-z.
% check
typeout{meaningmylist}
typeout{meaningmysortedlist}
end{document}
Here in the log output, with PDFLaTeX:
macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xyl
ophone, wäsh, edifice, édifice, wäsherei
macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, w
asn't, wish, wäsh, wäsher, wäsherei, édifice
and using XeLaTeX (which does not cut lines the same way):
macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xylo
phone, wäsh, edifice, édifice, wäsherei
macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, w
asn't, wish, wäsh, wäsher, wäsherei, édifice
The console output (again XeLaTeX) is still different, lines not cut:
macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xylophone, wäsh, edifice, édifice, wäsherei
macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, wasn't, wish, wäsh, wäsher, wäsherei, édifice
You can try this
This is taken over from https://tex.stackexchange.com/a/273084/4686 (code 5)
% ------------------------------------------------------------------
% Expandable routine to sort strings, based on a QuickSort algorithm
% and using pdfstrcmp.
% ------------------------------------------------------------------
% USAGE
% -----
% if using XeTeX:
% edefmysortedlist {QSfull{mylist}}, or explicit QSfull {foo, bar, zoo}
% if using PDFLaTeX: (and inputenc for accented letters)
% begingroup
% subdueutfviiienc
% globaledefmysortedlist {QSfull{mylist}}
% endgroup
documentclass{article}
ifdefinedXeTeXinterchartoks
letpdfstrcmpstrcmp
usepackage{fontspec}
else
usepackage[T1]{fontenc}
usepackage[utf8]{inputenc}% for PDFLaTeX
makeatletter
% this subdueutfviiienc allows é, à, etc... to survive as is to edef's.
newcommand*subdueutfviiienc {% to be used in a group
count@="C2
loop
lccode`~count@
lowercase{def~####1{noexpand~string####1}}%
ifnumcount@<"E0
advancecount@@ne
repeat
loop
lccode`~count@
lowercase{def~####1####2{noexpand~string####1string####2}}%
ifnumcount@<"F0
advancecount@@ne
repeat
loop
lccode`~count@
lowercase{def~####1####2####3{noexpand~string####1string####2string####3}}%
ifnumcount@<"F4
advancecount@@ne
repeat
}makeatother
% (if inputenc is used with 8bit encoding another approach would be needed)
fi
% CODE TAKEN FROM https://tex.stackexchange.com/a/273084/4686 (code 5)
% -------------------------------------------------------------------
makeatletter
longdefxintdothis #1#2xintorthat #3{fi #1}%
letxintorthat @firstofone
%
% use some (improbable) tokens as delimiters
catcode`! 3
catcode`? 3
catcode`; 3
%
% first we check if empty list (else qsfull@finish will not find a comma)
% we apply f-expansion to the argument to allow it to be a macro.
%
defQSfull #1{expandafterqsfull@aromannumeral-`0#1,!,?}%
%
% first check if input has only blanks, or is empty
defqsfull@a #1{ifx,#1xintdothisqsfull@afi
ifx!#1xintdothisqsfull@abortfi
xintorthat{qsfull@start #1}}%
defqsfull@abort #1?{}%
%
defqsfull@start {expandafterqsfull@finishromannumeral0qsfull@b,}%
defqsfull@finish ,#1{#1}% remove initial ,<space>
defqsfull@b ,#1#2,#3{ifx?#3xintdothisqsfull@emptylistfi
ifx!#3xintdothisqsfull@singletonfi
xintorthat qsfull@separate@a {}{}#1#2;#3}%
defqsfull@emptylist #1?{}%
defqsfull@singleton #1#2#3;!,?{, #3}%
%
defqsfull@separate@a #1#2#3;#4#5,%
% first pass, remove blanks in passing.
% no need to be extra efficient for that.
{%
ifx,#4expandafterqsfull@valueisblankfi
ifx!#4expandafterqsfull@separate@donefi
if1pdfstrcmp{#4#5}{#3}%
expandafterqsfull@separate@a@appendtogreater
elseexpandafterqsfull@separate@a@appendtosmaller
fi
#4#5?{#1}{#2}#3;%
}%
defqsfull@valueisblank ifx#1fi,#2?#3#4#5;{qsfull@separate@a {#3}{#4}#5;#2,}%
defqsfull@separate@a@appendtogreater #1?#2{qsfull@separate@a {#2, #1}}%
%
defqsfull@separate@a@appendtosmaller #1?#2#3{qsfull@separate@a {#2}{#3, #1}}%
%
defqsfull@separate@doneif#1fi #2?#3#4#5;?%
{%
qsfull@c #4,!,?, #5qsfull@c #3,!,?%
}%
% Now that the first pass is done, there are no more blank items.
% In particular here.
defqsfull@c ,#1#2,#3{ifx?#3xintdothisqsfull@emptylistfi
ifx!#3xintdothisqsfull@singletonfi
xintorthat qsfull@separate {}{}#1#2;#3}%
%
defqsfull@separate #1#2#3;#4#5,% blanks have already been filtered out.
{%
ifx!#4expandafterqsfull@separate@donefi
if1pdfstrcmp{#4#5}{#3}%
expandafterqsfull@separate@a@appendtogreater
elseexpandafterqsfull@separate@a@appendtosmaller
fi
#4#5?{#1}{#2}#3;%
}%
defqsfull@separate@appendtogreater #1?#2{qsfull@separate {#2, #1}}%
defqsfull@separate@appendtosmaller #1?#2#3{qsfull@separate {#2}{#3, #1}}%
%
%
catcode`! 12
catcode`? 12
catcode`; 12
makeatother
begin{document}
defmylist{book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't,
Cat, Xylophone, wäsh, edifice, édifice, wäsherei}
% use either a macro mylist or explicit list as QSfull argument.
ifdefinedXeTeXinterchartoks
edefmysortedlist{QSfull{mylist}}
else
{subdueutfviiiencglobaledefmysortedlist{QSfull{mylist}}}%
fi
mylistpar
medskip
becomes (notice how whitespaces are normalized in the process):
medskip
mysortedlist
medskip
For some reason due to the comparison being done by verb|pdfstrcmp| the é
comes after a-z.
% check
typeout{meaningmylist}
typeout{meaningmysortedlist}
end{document}
Here in the log output, with PDFLaTeX:
macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xyl
ophone, wäsh, edifice, édifice, wäsherei
macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, w
asn't, wish, wäsh, wäsher, wäsherei, édifice
and using XeLaTeX (which does not cut lines the same way):
macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xylo
phone, wäsh, edifice, édifice, wäsherei
macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, w
asn't, wish, wäsh, wäsher, wäsherei, édifice
The console output (again XeLaTeX) is still different, lines not cut:
macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xylophone, wäsh, edifice, édifice, wäsherei
macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, wasn't, wish, wäsh, wäsher, wäsherei, édifice
edited Apr 13 '17 at 12:34
Community♦
1
1
answered Oct 12 '16 at 8:52
jfbu
46k66148
46k66148
The complications with inputenc-made active characters are due to the fact we neededef
to get complete expansion. But the coding could be modified to achieve complete expansion under repeated expansion of first token. In fact code 3 et 4 of tex.stackexchange.com/a/273084/4686 do that. Then no need forsubdueutfviiienc
.
– jfbu
Oct 12 '16 at 9:51
add a comment |
The complications with inputenc-made active characters are due to the fact we neededef
to get complete expansion. But the coding could be modified to achieve complete expansion under repeated expansion of first token. In fact code 3 et 4 of tex.stackexchange.com/a/273084/4686 do that. Then no need forsubdueutfviiienc
.
– jfbu
Oct 12 '16 at 9:51
The complications with inputenc-made active characters are due to the fact we need
edef
to get complete expansion. But the coding could be modified to achieve complete expansion under repeated expansion of first token. In fact code 3 et 4 of tex.stackexchange.com/a/273084/4686 do that. Then no need for subdueutfviiienc
.– jfbu
Oct 12 '16 at 9:51
The complications with inputenc-made active characters are due to the fact we need
edef
to get complete expansion. But the coding could be modified to achieve complete expansion under repeated expansion of first token. In fact code 3 et 4 of tex.stackexchange.com/a/273084/4686 do that. Then no need for subdueutfviiienc
.– jfbu
Oct 12 '16 at 9:51
add a comment |
Thanks for contributing an answer to TeX - LaTeX Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f333646%2fsorting-a-comma-separated-list-with-latex%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
3
Welcome to TeX.SX! Knowing a bit more about your failed attempt and the kind of data you need to sort would be helpful.
– egreg
Oct 11 '16 at 11:30
1
Sorting strings of ASCII characters is feasible (although non yet supported by
expl3
); it would become much more complicated if words with accents and so on are involved.– egreg
Oct 11 '16 at 12:37