![使用 Lua 对名称列表进行排序](https://linux22.com/image/351060/%E4%BD%BF%E7%94%A8%20Lua%20%E5%AF%B9%E5%90%8D%E7%A7%B0%E5%88%97%E8%A1%A8%E8%BF%9B%E8%A1%8C%E6%8E%92%E5%BA%8F.png)
我想定义一个\directlua
类似这样的命令:
\sort{c, b, a}
并输出a, b, c
至文档。
答案1
在 ConTeXt 中您不必重新发明轮子。
\def\sort#1{%
\ctxlua{
context(
table.concat(
table.sorted(
utilities.parsers.settings_to_array([[#1]]) ) , ", " ) )
}}
\starttext
\sort{c, b, a}
\stoptext
您还可以通过从 ConTeXt 中包含适当的 Lua 标头将其与 LaTeX 一起使用。
\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}
输出类似。
要省略空条目(空字符串),必须编写一个额外的辅助函数,但我在 ConTeXt 中找不到该函数。但是,并排的多个空条目似乎会混淆至少一个函数,即\sort{,,,,a}
会产生虚假的逗号。
\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}
答案2
这是一个可能的解决方案。主 Lua 函数,称为dojob
,将输入字符串转换为 Lua 表(通过调用辅助 Lua 函数string_to_table
),执行简单排序,并将表元素输出为字符串,元素之间用“ ”(“逗号和空格”)分隔,
。任何前导或尾随空格字符和逗号都会被自动丢弃。
dojob
可以通过名为 的 LaTeX 宏从 LaTeX 文档主体中访问Lua 函数\sort
。
另外:函数中的大部分 Lua 代码string_to_table
来自本网站(查找标题“方法:仅使用 string.gsub”以获取有关代码工作原理的更多详细信息。)为了确保万无一失,我添加了一个例程,用于从表条目中删除前导和尾随空格。
排序程序很简单。我相信您的逗号分隔列表不会太长,因此需要更高效的排序算法(例如 QuickSort)以避免陷入困境。
% !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}