Я пытаюсь решить проблему с $
и $$
в формулах, чтобы выполнить автоматическую маркировку этих формул, включая добавление в дерево структуры. Вариант с \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}