将参数从 TeX 传递给 Lua 函数

将参数从 TeX 传递给 Lua 函数

以下代码是将参数从 TeX 传递到 Lua 的简单示例。直接传递参数(不带 的版本\luastringN)会出错。

(./luafunction.aux)./luafunction.lua:2: attempt to concatenate local 's' (a nil value)
stack traceback:
        ./luafunction.lua:2: in function 'joinstring'
        [\directlua]:1: in main chunk.
\joinstring #1#2-> \directlua {joinstring(#1, #2)}

l.19 \joinstring{foo}{bar}

\luastringN我注意到其他代码在将参数从 TeX 传递到 Lua 时使用了宏,所以我也这么做了。但这完全是 Cargo Cult 编程,因为我不知道为什么。luacode手册中的文档不是很有启发性。在 v1.2a 手册第 3 页第 1.2 节中\luastringN,有文档记录,它讨论了转义特殊字符。但我的示例中没有特殊字符。我不明白从 TeX 传递到 Lua 需要什么特殊处理。感谢您的解释 - 请随意简化它。

此外,这是对“LuaLaTeX 在 lua 中设置路径”问题的回答提到应该使用token.get_macro。v 1.10 手册第 10.6.4 页上的文档luatex说:

get_macro 函数可用于获取宏的内容

但我不确定这是什么意思。另外,我在 TeX SE 中搜索了token.get_macro,得到了两个结果。

那么这是一个更好的选择吗?如果是,为什么?该get_macro函数到底有什么用?

\documentclass{article}
\usepackage{luacode}
\usepackage{filecontents}
\begin{filecontents*}{luafunction2.lua}
function joinstring (s, t)
 tex.sprint(s .. t)
end

\end{filecontents*}
\directlua{require "luafunction2.lua"}
\begin{document}

\newcommand\joinstring[2]
{
  % \directlua{joinstring(#1, #2)}
  \directlua{joinstring(\luastringN{#1}, \luastringN{#2})}
}

\joinstring{foo}{bar}

\end{document}

聊天室讨论开始于这里

答案1

这里所做\luastringN的只是提供一个包装器,\luaescapestring加上一些皱纹。我只会把它写出来,至少对于“练习”文件来说

\documentclass{article}
\usepackage{filecontents}
\begin{filecontents*}{luafunction2.lua}
function joinstring (s, t)
 tex.sprint(s .. t)
end
\end{filecontents*}
\directlua{require "luafunction2.lua"}
\begin{document}

\newcommand\joinstring[2]
{%
  \directlua{joinstring(
    "\luaescapestring{\unexpanded{#1}}",
    "\luaescapestring{\unexpanded{#2}}")
  }%
}

\joinstring{foo}{bar}

\end{document}

请注意,\luaescapestring执行 ( e-type) 扩展,因此我们需要\unexpanded避免发生奇怪的事情。还要注意"字符,这些字符是告诉 Lua 我们正在传递一个字符串所必需的。我们不必担心"TeX 输入中的任何内容,因为\luaescapestring它们是安全的。

答案2

由于 Lua 函数tex.sprint需要对字符串进行操作(字符串常量、类型变量string或可以string动态强制转换为类型的内容),因此将 LaTeX 端宏定义为

\newcommand\joinstring[2]{\directlua{joinstring(#1,#2)}}

然后运行

\joinstring{foo}{bar}

是错误的,因为foobar不会自动转换为 Lua 识别的字符串。事实上,您重现的错误消息表明 Lua 认为foobar属于 类型nil。 类型的变量nil肯定会使指令..中的字符串连接操作出错tex.sprint ( s .. t )

两个明显的补救措施是

  1. 将 的参数放在显式引号中\joinstring,即运行

    \joinstring{"foo"}{"bar"}
    
  2. 将 LaTeX 宏定义为

    \newcommand\joinstring[2]{\directlua{joinstring("#1","#2")}}
    

    我想有人会说,\luastring{#1}尤其是对该方法的\luastringN{#1}详细说明(例如,禁止扩展) 。它们还更强大,因为它们可以处理参数中不平衡的(单引号和双引号);不平衡的双引号会破坏该方法。#1"#1""#1"


实现第二个想法的完整 MWE —— 请注意,对于手头的简单代码,无需加载包luacode

在此处输入图片描述

\documentclass{article}
\directlua{function joinstring (s,t) tex.sprint (s..t) end}
\newcommand\joinstring[2]{\directlua{joinstring("#1","#2")}}     
\begin{document}
\joinstring{foo}{bar}
\end{document}

答案3

\luaescapestring作为其他答案中基于解决方案的替代方案,您还可以使用token库将参数从 TeX 传递到 Lua。这会导致速度略有提高,因为 LuaTeX 不必转义字符串以便 Lua 再次解析它。因此,您可能会考虑它,尤其是当您期望长字符串时。此外,这避免了混合 TeX 和 Lua 代码,如果您以后决定使用\luafunction(或\luadef) 的代码,这会有所帮助。

无论如何,你首先必须决定是否需要 ( e-type) 扩展。token函数总是会扩展参数,所以\unexpanded如果你不想这样做,你必须应用。然后你可以使用token.scan_argument它来读取直接给出的参数整个 Lua 代码。如果您决定读取扩展参数,您也可以完全通过 Lua 处理参数读取,但适用略有不同的扫描规则。特别是在简单情况下,字符串参数不需要括号。

以下是一些示例,可查看不同选项的实际效果:

\documentclass{article}
\usepackage{luacode}
\usepackage{filecontents}
\begin{filecontents*}{luafunction2.lua}
function joinstring (s, t)
 tex.write(s, ', ' , t, ': ')
 tex.sprint(s .. t .. '.')
end
\end{filecontents*}
\directlua{require "luafunction2.lua"}
\begin{document}

\newcommand\joinstring[2]{
  \directlua{joinstring(token.scan_argument(), token.scan_argument())}%
  {\unexpanded{#1}}{\unexpanded{#2}}
}

\newcommand\expandedjoinstring[2]
{
  \directlua{joinstring(token.scan_argument(), token.scan_argument())}%
  {#1}{#2}%
}

\newcommand\otherexpandedjoinstring
{
  \directlua{joinstring(token.scan_argument(), token.scan_argument())}%
}

\newcommand\foo{foo}
\newcommand\Bar{bar}
\verb|\joinstring{foo}{bar}|: \joinstring{foo}{bar}\\
\verb|\joinstring{\foo}{\Bar}|: \joinstring{\foo}{\Bar}\\
\verb|\joinstring foo bar|: \joinstring foo bar\\
\verb|\expandedjoinstring{foo}{bar}|: \expandedjoinstring{foo}{bar}\\
\verb|\expandedjoinstring{\foo}{\Bar}|: \expandedjoinstring{\foo}{\Bar}\\
\verb|\expandedjoinstring foo bar|: \expandedjoinstring foo bar\\
\verb|\otherexpandedjoinstring{foo}{bar}|: \otherexpandedjoinstring{foo}{bar}\\
\verb|\otherexpandedjoinstring{\foo}{\Bar}|: \otherexpandedjoinstring{\foo}{\Bar}\\
\verb|\otherexpandedjoinstring foo bar|: \otherexpandedjoinstring foo bar\\
\end{document}

在此处输入图片描述

相关内容