使用 Lua 对名称列表进行排序

使用 Lua 对名称列表进行排序

我想定义一个\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}

相关内容