使用 luatex 将列表拆分为表格

使用 luatex 将列表拆分为表格

我正在寻找一个可以做类似事情的 luatex 解决方案。

\split{a;b;c;d;e}

此命令应生成类似这样的表格。

\begin{tabular}{|*{5}{c|}}
\hline
a & b & c & d & e \\
\hline
\end{tabular}

我正在尝试这样的代码,但是在编译和调试时遇到很多问题,不太容易。

\documentclass[10pt,oneside]{article}
\usepackage{luatextra}

\newcommand{\split}[1]{%
\directlua{
    lst = string.split("#1",";")
    max = \luaescapestring{##lst}
    tex.print(format.string([[\string\begin{tabular}{|*{\%i}{c|}]],max))
    tex.print([[\string\hline]])
    for i,x in ipairs(lst) do
         if i == max then
             tex.print(format.string([[\%s \string\string\]],x)
         else
             tex.print(format.string([[\%s \&]],x)
         end
    end
    tex.print([[\string\hline]])
    tex.print([[\string\end{tabular}]])}}

\begin{document}
\split{a;b;c;d;e}
\end{document}

编辑 1: 以下代码对我有用。

\documentclass[10pt,oneside]{article}
\usepackage{luatextra}

\begin{luacode*}
  function split(input)
    local lst = string.split(input,";")
    local max = #lst
    tex.print(string.format([[\begin{tabular}{|*{%i}{c|}}]],max))
    tex.print([[\hline]])
    for i, x in ipairs(lst) do
       if i == max then
         tex.print(string.format([[%s \\]],x))
       else
         tex.print(string.format([[%s & ]],x))
       end
    end
    tex.print([[\hline\end{tabular}]])
  end
\end{luacode*}

\newcommand{\split}[1]{\directlua{split("#1")}}

\begin{document}
\split{a;b;c;d;e}
\end{document}

答案1

Luastring没有split默认拆分连接有大量的设计和实施实例。

使用 TeX 编写 Lua 会使特殊字符的转义成为一个问题。luacode提供了多种编写 Lua 代码的方法和环境。文档提供概述,说明如何对每种方法中的字符进行转义。

因为这是一个练习,所以下面的示例不使用luatextra或而是直接luacode使用原语。\directlua

特殊字符:

  • 百分号%是 TeX 中的注释字符,因此示例定义\%扩展为百分号字符。

  • \#被定义为井号字符的转义。

  • \\被定义为反斜杠的转义。注意:有些方法luacode使用输入\\双倍的双反斜杠,并\string\在环境除外的情况下使用单反斜杠luacode*,其中反斜杠以逐字方式书写。

由于 TeX 会用空格替换行尾,因此\directlua将是一行很长的代码,并且总是在第一行中报告错误。因此,组内的行尾行为被更改为使用换行符 (LF/0x10)。因为 TeX 读取整行执行行的内容时,末尾的百分号注释\endgroup会禁用读取的行末字符。否则,Missing如果在序言中使用新行字符,TeX 会将其视为普通字符,从而导致错误 \begin{document}`,否则行末字符将作为字符(当前字体的第 10 个位置)出现在排版输出中。

完整示例:

% arara: lualatex
\documentclass[10pt,oneside]{article}

% Function string:split
%
% Source: http://lua-users.org/wiki/SplitJoin (GavinKistner)
%
% Written for 5.0; could be made slightly cleaner with 5.1
% Splits a string based on a separator string or pattern;
% returns an array of pieces of the string.
% (May optionally supply a table as the third parameter
% which will be filled with the results.)
\begingroup
  \makeatletter
  \let\%\@percentchar
  \let\\\@backslashchar
  \edef\#{\string#}%
  \catcode10=12 %
  \endlinechar=10 %
\directlua{%
  function string:split( inSplitPattern, outResults )
    if not outResults then
      outResults = { }
    end
    local theStart = 1
    local theSplitStart, theSplitEnd = string.find( self, inSplitPattern, theStart )
    while theSplitStart do
      table.insert( outResults, string.sub( self, theStart, theSplitStart-1 ) )
      theStart = theSplitEnd + 1
      theSplitStart, theSplitEnd = string.find( self, inSplitPattern, theStart )
    end
    table.insert( outResults, string.sub( self, theStart ) )
    return outResults
  end
}\directlua{%
  function semicolon_split(input)
    local lst = input:split(";")
    local max = \#lst
    tex.print(string.format([[\\begin{tabular}{|*{\%i}{c|}}]],max))
    tex.print([[\\hline ]])
    for i, x in ipairs(lst) do
       if i == max then
         tex.print(string.format([[\%s\\\\]],x))
       else
         tex.print(string.format([[\%s&]],x))
       end
    end
    tex.print([[\\hline\\end{tabular}]])
  end
}\endgroup%

\newcommand{\split}[1]{%
  \directlua{semicolon_split("\luatexluaescapestring{#1}")}%
}

\begin{document}
\split{a;b;c;d;e}
\end{document}

结果

为了进行比较,与环境相同luacode。其中,%#可以直接使用或用作\%\#。反斜杠可通过较长的获得\string\,更准确地说,\不是有效标记,因此\string应用于以开头的下​​一个命令\。宏\\生成双反斜杠。

% arara: lualatex
\documentclass[10pt,oneside]{article}
\usepackage{luacode}

% Function string:split
%
% Source: http://lua-users.org/wiki/SplitJoin (GavinKistner)
%
% Written for 5.0; could be made slightly cleaner with 5.1
% Splits a string based on a separator string or pattern;
% returns an array of pieces of the string.
% (May optionally supply a table as the third parameter
% which will be filled with the results.)
\begin{luacode}
  function string:split( inSplitPattern, outResults )
    if not outResults then
      outResults = { }
    end
    local theStart = 1
    local theSplitStart, theSplitEnd = string.find( self, inSplitPattern,
    theStart )
    while theSplitStart do
      table.insert( outResults, string.sub( self, theStart, theSplitStart-1 ) )
      theStart = theSplitEnd + 1
      theSplitStart, theSplitEnd = string.find( self, inSplitPattern, theStart )
    end
    table.insert( outResults, string.sub( self, theStart ) )
    return outResults
  end
\end{luacode}
\begin{luacode}
  function semicolon_split(input)
    local lst = input:split(";")
    local max = #lst
    tex.print(string.format([[\string\begin{tabular}{|*{%i}{c|}}]],max))
    tex.print([[\\hline ]])
    for i, x in ipairs(lst) do
       if i == max then
         tex.print(string.format([[%s\\]],x))
       else
         tex.print(string.format([[%s&]],x))
       end
    end
    tex.print([[\string\hline\string\end{tabular}]])
  end
\end{luacode}

\newcommand{\split}[1]{%
  \luadirect{semicolon_split("\luatexluaescapestring{#1}")}%
}

\begin{document}
\split{a;b;c;d;e}
\end{document}

luacode*如果不需要 TeX 宏、TeX 参数等,环境可能是最容易使用的:

\begin{luacode*}
  function semicolon_split(input)
    local lst = input:split(";")
    local max = #lst
    tex.print(string.format([[\begin{tabular}{|*{%i}{c|}}]],max))
    tex.print([[\hline ]])
    for i, x in ipairs(lst) do
       if i == max then
         tex.print(string.format([[%s\\]],x))
       else
         tex.print(string.format([[%s&]],x))
       end
    end
    tex.print([[\hline\end{tabular}]])
  end
\end{luacode*}

答案2

LuaTeX 必须string.explode()用一个带分隔符的字符串创建一个字符串表,以适合您的情况。(有关详细信息,请参阅 LuaTeX 的文档)。

但你的问题回答起来就简单多了:

\documentclass{article}
\usepackage{luacode}

\begin{luacode}
split=function(inputstr)
    local str,cnt = string.gsub(inputstr,";"," & ")
    tex.sprint("\\begin{tabular}{|*{",cnt + 1,"}{c|}}")
    tex.sprint("\\hline", str, "\\\\\\hline\\end{tabular}")
end
\end{luacode}

\newcommand{\split}[1]{\luaexec{split(\luastring{#1})}}

\begin{document}
\split{a;b;c;d;e}
\end{document}

您可以用 替换字符串中的;&

结果:

带字符的表格


编辑 1:将 long 替换"\lualatexescapestring{..}"为 luacode 包中更简单的\luastring{..}定义。感谢 Mico 的提示。编辑 2:使函数更通用

相关内容