如何使用lua重写tex文件

如何使用lua重写tex文件

我尝试解决公式中 和 的问题$$$自动标记这些公式,包括在结构树中添加。\grabinline或的变体\grabdisplay对我来说不起作用,因为当我尝试使用 时会出错equation。 最近我读到我可以通过 处理我自己的文件lualatex。 首先,我尝试简单地替换$$和 ,$如果之前没有\字符,但这不仅不起作用,而且当我尝试重写它时我的文件被损坏了,我的意思是,它会添加新的奇怪的行。

请帮帮我,我该如何解决这个问题,我指的是文件损坏的问题,请向我解释为什么会发生这种情况?

test.tex

\documentclass{article}
\directlua{require("test.lua")}
\pagestyle{empty}
\begin{document}
test
$$a+b=a^b$$ $a-b=a/b$
\end{document}

test.lua

f=io.open(tex.jobname..".tex","r+")
lines=f:lines()
for line in lines do
line=line:gsub("([^\\]?)$$(.+-)$$","%1\\[%2\\]")
line=line:gsub("([^\\]?)$(.+-)$","%1\\(%2\\)")
texio.write_nl("line of file "..line)
f:write(line)
end
f:close()

答案1

这个问题与 TeX 无关,这是读取和写入同一文件时出现的一般问题。那么到底发生了什么?

你可能得到的输出是

\documentclass{article}
\documentclass{article}t.lua")}
t.lua")}le{empty}
le{empty}cument}
cument}a+b=a^b$$ $a-b=a/b$
a+b=a^b$$ $a-b=a/b$

发生这种情况的原因是,打开原始文件后,您位于第一行的第一个字节。然后使用lines,您读取第一行:\documentclass{article}。之后,您在行中的位置是第二行的开头。在这里您发出f:write,因此第一个未修改的行被写入文件中的当前位置,即第二行。它会覆盖现有内容。

现在,该文件包含:

\documentclass{article}
\documentclass{article}t.lua")}
\pagestyle{empty}
\begin{document}
test
$$a+b=a^b$$ $a-b=a/b$
\end{document}

并且您当前的位置位于第二行的末尾\documentclass{article}。现在您的下一次lines迭代将读取该行的其余部分,因此您得到t.lua")}。然后您位于第三行的开头,并用刚刚读取的文本覆盖它,因此您得到

documentclass{article}
\documentclass{article}t.lua")}
t.lua")}le{empty}
\begin{document}
test
$$a+b=a^b$$ $a-b=a/b$
\end{document}

对每一行重复此操作,直到获得观察到的文件。

您可以在这里学到什么教训:请勿在读取文件时覆盖它!

相比之下,其他一些编程语言包含函数,例如 Python 的readlines,乍一看与 Lua 的 类似io.lines。但是例如 Python 的readlines直接将所有行读入数组,而 Lua 在循环的每次迭代中只读取一行。因此,那里的类似代码不会出现如此明显的问题,因为读取和写入明显分开:仅在 期间读取readline,之后写入。

无论如何,在 TeX 运行期间重写 TeX 源文件是非常危险的,而且不兼容(Windows 在编辑打开的文件时是明智的)。

process_input_buffer如果您只想一次更改一行,则使用起来更安全、更简单。您可以使用status.input_ptr它仅影响特定文件中的行:(我在此过程中修复了模式)

luatexbase.add_to_callback("process_input_buffer", function(line)
  if status.input_ptr ~= 1 then return end -- Only change lines of the main file
  texio.write_nl("line of file "..line)
  print(line:match("([^\\]?)$$(.-)$%$"))
  return line:gsub("([^\\]?)$$(.-)$%$","%1\\[%2\\]")
             :gsub("([^\\]?)$(.-)%$","%1\\(%2\\)")
end, "my_math_rewrite")

即使这危险性要小得多,我仍然建议您寻找无需重写输入行即可实现目标的方法。

答案2

(有点晚了,但希望仍然有用)

这是一个不创建新文本文件的解决方案。相反,它“即时”工作,本质上就像一个预处理器,并分别用 LaTeX 首选表达式替换匹配的$$和,如下图所示:$TeX 开始进行扩展宏等常规工作。

创建一个新的输出文本文件,以写出输入的即时修改内容,留作单独的练习。

为了将其从概念验证阶段推进到足以在实际工作中发挥作用的阶段,当然还必须添加代码来测试预处理器检查的材料是否恰好处于逐字模式或包含在 URL 字符串中。在这些和类似情况下,不应执行任何替换,对吗?

在此处输入图片描述

% !TEX TS-program = lualatex

%% Create external file to store Lua code:
\RequirePackage{filecontents}
\begin{filecontents*}{test.lua}
function substitute_dollar_symbols ( line )
    line = line:gsub ( "([^\\]?)$$(.+-)$$" , "%1\\[%2\\]" )
    line = line:gsub ( "([^\\]?)$(.+-)$"   , "%1\\(%2\\)" )
    return line
end
\end{filecontents*}

\documentclass{article}
%% Load Lua code from external file:
\directlua{require("test.lua")}

%% Create two LaTeX utility macros to (a) assign Lua 
%% function to the "process_input_buffer" callback 
%% and (b) remove the function from that callback:
\newcommand\SubstituteDollarSymbolsOn{%
  \directlua{luatexbase.add_to_callback (
    "process_input_buffer", 
    substitute_dollar_symbols , 
    "substitute_dollar_symbols" )}}
\newcommand\SubstituteDollarSymbolsOff{%
  \directlua{luatexbase.remove_from_callback (
    "process_input_buffer",
    "substitute_dollar_symbols" )}}

%% Activate the Lua function at start of document:
\AtBeginDocument{\SubstituteDollarSymbolsOn}

\begin{document}
test
$$a+b=a^b$$ $a-b=a/b$ % $$ $
abc $$uvw$$
\end{document}

相关内容