I want to define a command using \directlua
that looks something like:
\sort{c, b, a}
and outputs a, b, c
to the document.
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It only takes a minute to sign up.
Sign up to join this communityIn ConTeXt you do not have to reinvent the wheel.
\def\sort#1{%
\ctxlua{
context(
table.concat(
table.sorted(
utilities.parsers.settings_to_array([[#1]]) ) , ", " ) )
}}
\starttext
\sort{c, b, a}
\stoptext
You can also use it with LaTeX by including the appropriate Lua headers from ConTeXt.
\documentclass{article}
\directlua{
dofile(kpse.find_file("l-lpeg.lua"))
dofile(kpse.find_file("util-sto.lua"))
dofile(kpse.find_file("util-prs.lua"))
}
\def\sort#1{%
\directlua{\unexpanded{
tex.sprint(
table.concat(
table.sorted(
utilities.parsers.settings_to_array([[#1]]) ) , ", " ) )
}}}
\begin{document}
\sort{c, b, a}
\end{document}
The output is similar.
To omit empty entries (empty string) one has to write one additional helper function, which I could not find in ConTeXt. However, multiple empty entries side by side seem to confuse at least one of the functions, i.e. \sort{,,,,a}
will produce spurious commas.
\documentclass{article}
\directlua{
dofile(kpse.find_file("l-lpeg.lua"))
dofile(kpse.find_file("l-string.lua"))
dofile(kpse.find_file("util-sto.lua"))
dofile(kpse.find_file("util-prs.lua"))
function table.strip_empty(tab)
for k, v in pairs(tab) do
if ( string.strip(v) == "" ) then
table.remove(tab, k)
end
end
return tab
end
}
\def\sort#1{%
\directlua{\unexpanded{
tex.sprint(
table.concat(
table.sorted(
table.strip_empty(
utilities.parsers.settings_to_array([[#1]]) ) ) , ", " ) )
}}}
\begin{document}
\sort{, d, , f, c, b, a, }
\end{document}
\sort{c, ,b, a,}
)?
Here's a possible solution. The main Lua function, called dojob
, converts the input string into a Lua table (via a call to an auxiliary Lua function called string_to_table
), performs a simple sort, and outputs the table elements as a string, with the elements separated by ",
" ("comma&space"). Any leading or trailing whitespace characters and commas are discarded automtically.
The Lua function dojob
may be accessed from within the body of a LaTeX document via the LaTeX macro called \sort
.
Aside: Much of the Lua code in the string_to_table
function was obtained from this site. (Look for the header "Method: Using only string.gsub" for more details on how the code works.) For good measure, I added a routine that removes leading and trailing whitespace from the table entries.
The sorting routine is simple. I trust your comma-separated list isn't so long as to require a more efficient sorting algorithm (e.g., QuickSort) in order to avoid getting bogged down.
% !TeX program = lualatex
\documentclass{article}
%% Lua-side code
\usepackage{luacode}
\begin{luacode}
function string_to_table (str)
sep = ","
fields = {}
str:gsub( "([^"..sep.."]*)" .. sep ,
function(c)
c = string.gsub ( c, "^%s*(.-)%s*$", "%1" )
table.insert (fields, c)
end)
return fields
end
function dojob ( s )
-- append "," (if needed) to end of string
if (string.sub(s,-1) == ",") then else s = s.."," end
-- convert string to table
t = string_to_table ( s , "," )
-- sort the table entries
table.sort ( t , function(a,b) return a<b end)
-- convert table to string, with items separated by commas
s = table.concat ( t, ", " )
-- remove any leading whitespace and comma characters, output the string
tex.sprint ( (string.gsub( s, "^[,%s]*(.*)$", "%1" ) ) )
end
\end{luacode}
%% TeX-side code
\newcommand\sort[1]{\directlua{dojob(\luastring{#1})}}
\begin{document}
\sort{c, b, a}
\sort{Carla , Eric , Anna Michelle, Brenda , Daniel}
\sort{Eric,Carla,Brenda,Anna Michelle,Daniel,,}
\sort{aaa,15}
\end{document}