使用 LuaLatex 从 JSON 文件加载字段

使用 LuaLatex 从 JSON 文件加载字段

我想从模拟返回的单个 JSON 文件中加载大量数字到我的文档中。为此,我到目前为止遵循了这个 stackchange 答案但对于多个值,我必须在整个文档中多次加载 JSON 文件(我是 LuaLatex 的新手,所以也许我遗漏了一些重要的东西)。我想要的是这样的:

\documentclass{article}
\usepackage{luacode}

\begin{document}

\begin{luacode}
function read(file)
    local handler = io.open(file, "rb")
    local content = handler:read("*all")
    handler:close()
    return content
end
JSON = (loadfile "JSON.lua")()
local table = JSON:decode(read("recipes.json"))
\end{luacode}

The fat content of the recipe \directlua{tex.print(table['recipe']
['title'])} is \directlua{tex.print(table['recipe']
['fat'])}.

\end{document}

实现这一目标的最干净的方法是什么?

答案1

我找到了答案:在上面的例子中,相关变量(表)被定义为本地变量。这就是为什么它在后续的 lua 调用中无法访问。解决方案如下

\documentclass{article}
\usepackage{luacode}

\begin{document}

% load json file
\begin{luacode}
function read(file)
    local handler = io.open(file, "rb")
    local content = handler:read("*all")
    handler:close()
    return content
end
JSON = (loadfile "JSON.lua")()
table = JSON:decode(read("recipes.json"))
\end{luacode}

The fat content of the recipe \directlua{tex.print(table['recipe']
['title'])} is \directlua{tex.print(table['recipe']
['fat'])}.

\end{document}

答案2

我想在根据这个问题进行自己的测试后扩展@user45893的答案,并且链接的一。

  1. -environmentluacode可以放在序言中,这样可以在其下方创建自定义命令,以便在您需要在文档中打印大量外部值时减少冗长程度。
  2. 您可以使用 lua 函数格式化数字string.format(),该函数使用c++printf语法。 然而,
  3. 该命令\directlua{}没有转义%符号,因此需要使用\luaexec{}包中的命令\usepackage{luatextra}。此包已包含luacode环境。
  4. 给定的解决方案使用了我无法找到的外部文件JSON.lua。无依赖的解决方案是函数utilities.json.tolua()
  5. 环境luacode接受 LaTeX 命令。例如描述路径。这允许轻松地将同一目录中的多个文件加载到多个变量中。

我完成的 MWE 如下所示:

\documentclass{article}
\usepackage{luatextra}
\newcommand{\dataPath}{path/to/folder}

% load the data file supposedly containing 'title' and 'numbers'
\begin{luacode}
  require("lualibs.lua")
  local f = io.open('\dataPath/file.json', 'r')
  local s = f:read('*a')
  f:close()
  data =  utilities.json.tolua(s)
\end{luacode}

% Simple print function
\newcommand{\printlua}[1]{\luaexec{tex.sprint(#1)}}

% Example: formatting a number with an optional formatting argument
\newcommand{\printnumber}[2][i]{\printlua{string.format("\%#1", #2)}}

\begin{document}
Simple print function: \printlua{data['title']}.

% '%i' for signed integer (default of the command).
Default number format: \printnumber{data['numbers']['number1']}. 

% '%.2f' for decimal float with 2 digits after the decimal point .
Different number format: \printnumber[.2f]{data['numbers']['number1']}.
\end{document}

注意事项:

  • 对于列表元素来说,该方法相当有限。我只找到了一种通过其显式索引调用它们的方法: fe printnumber{data['listofnumbers'][5]}
  • 科学记数法 ( ) 的格式%e返回 fe 3.9265e+2,这在 LaTeX 数学模式下非常难看。对于非常大或非常小的数字,我建议在生成数据文件时将它们另外存储为预格式化的字符串,并使用此解决方案直接用 加载它们\printlua{}
  • 该命令luaexec{}(或tex.sprint(),我不确定哪个是原因)不只是返回值,而是将其嵌入到组中。这妨碍了其他 LaTeX 命令对值的进一步格式化处理。

例如-package\num{}的-command siunitx

\num{\printnumber[.2e]{data['numbers']['number1']}}
% gives:
% Package siunitx Error: Invalid number '\begingroup \escapechar 92...

注意:我没有任何 lua 经验,请随意按照通常的代码约定编辑格式。

相关内容