我正在寻找一个可以做类似事情的 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:使函数更通用