如何让下面的代码通过编译?
\documentclass{article}
\newcommand*{\mycommand}{\directlua{for i = 1, 10 do tex.sprint(i\hskip1cm) end}} %does not work
%\newcommand*{\mycommand}{\directlua{for i = 1, 10 do tex.sprint(i\\hskip1cm) end}} %does not work
%\newcommand*{\mycommand}{\directlua{for i = 1, 10 do tex.sprint(i) end}} %works
\begin{document}
test \mycommand
\end{document}
答案1
首先,你想将变量的值i
与标记连接起来\hskip1cm
,但表达式i\hskip1cm
不是有效的lua表达式。你需要创建\hskip1cm
一个lua字符串并将其与的值连接起来i
。即:
tex.sprint(i .. "\hskip1cm")
但是,这也行不通,因为引号内的\
是 lua 的转义字符,因此\h
将被解释为转义序列,而 lua 会抱怨这\h
是无效的转义序列。因此,您必须“转义转义”:
tex.sprint(i .. "\\hskip1cm")
对于 lua 来说这没什么问题,但对于 TeX 来说却会出现问题,因为它会\\
出现在 tex 定义内部,而 TeX 会尝试扩展它,从而导致麻烦。
您可以通过两种不同的方式避免此麻烦:
第一个解决方案
这是首选。将您的 lua 代码移至外部文件。例如,创建一个名为 的文件mycommand.lua
,其中包含实现您的代码的 lua 函数:
-- mycommand.lua
function mycommand()
for i = 1, 10 do
tex.sprint(i .. "\\hskip1cm")
end
end
然后,在您的tex
文件中,运行 lua 文件(定义该函数并使其可用于 lua),并定义\mycommand
执行该函数mycommand
。这样:
\documentclass{article}
\directlua{dofile("mycommand.lua")} % This defines the lua function mycommand()
\newcommand*{\mycommand}{\directlua{mycommand()}} % This defines the tex macro
\begin{document}
test \mycommand
\end{document}
请注意, 的扩展\mycommand
现在不包含任何\\
,因此 TeX 很满意。当 TeX 扩展 时\mycommand
,这会导致mycommand()
执行该函数,这将把 的连接“输出”到 tex 文档中i.."\\hskip1cm"
,结果为1\hskip1cm2\hskip1cm3\hskip1cm
etc,这是可以的。生成的 pdf 显示预期结果:
第二种解决方案
这比较丑陋,一般不推荐。您可以将任何 tex 宏放入 中\luatexluaescapestring
,这将修改其扩展,以便结果为有效的 lua 字符串。因此,如果您编写例如"\luatexluaescapestring{\foo}"
这将生成一个包含 扩展的复杂字符串\foo
,但每个扩展都\
转义为\\
。将其应用于您的示例:
\documentclass{article}
\newcommand*{\mycommand}{%
\directlua{for i = 1, 10 do tex.sprint(i .. "\luatexluaescapestring{\hskip1cm}") end}
}
\begin{document}
test \mycommand
\end{document}
请注意,仍然需要用双引号括起来,才能得到可以连接到变量值的 lua 字符串i
。
答案2
对于上面的解决方案 1,为了避免反斜杠转义,我建议使用括号版本的 lua 字符串(= 字符的数量可以是任意数量,只要您使用相同的两次):
-- mycommand.lua
function mycommand()
for i = 1, 10 do
tex.sprint(i .. [===[\hskip1cm]===])
end
end
如果有足够声誉的人可以回复此答案,请这样做。
答案3
可以将所有小部分lua
代码放在一个文件中:
\documentclass{article}
\usepackage{luacode}
\begin{luacode}
function mycommand()
for i = 1, 10 do
tex.sprint(i .. "\\hskip1cm")
end
end
\end{luacode}
\newcommand*{\mycommand}{\directlua{mycommand()}}
\begin{document}
test \mycommand
\end{document}