The problem is not TeX related, it is a general problem with reading and writing the same file. So what is going on?
The output you probably get is
\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$
This happens because after opening your original file, you are at the first byte of the first line. Then using lines
, you read the first line: \documentclass{article}
. After that, your position in the line is the beginning of the second line. Here you issue f:write
, so the first, unmodified, line is written to the current position in the file, which is the second line. It overwrites existing content.
So now, the file contains:
\documentclass{article}
\documentclass{article}t.lua")}
\pagestyle{empty}
\begin{document}
test
$$a+b=a^b$$ $a-b=a/b$
\end{document}
and your current position is at the end of the second \documentclass{article}
.
Now your next lines
iteration reads the rest of the line, so you get t.lua")}
.
Then you are at the start of the third line and you overwrite it with the just read text, so you get
documentclass{article}
\documentclass{article}t.lua")}
t.lua")}le{empty}
\begin{document}
test
$$a+b=a^b$$ $a-b=a/b$
\end{document}
This repeats for every line, until you get the file you observed.
Which lesson can you learn here:
Do not overwrite a file while you are still reading from it!
In contrast some other programming languages contain functions, like Python with readlines
, which on the first glance look similar to Lua's io.lines
. But e.g. Python's readlines
directly reads all lines into an array, while Lua only reads one line at a time in every iteration of the loop. So no quite so obvious problems appear with similar code there because reading and writing is clearly separated: Reading only during readline
, writing afterwards.
Anyway rewriting your TeX source file during the TeX run is very dangerous and also not compatible (Windows is sensible when it comes to editing open files).
It is much safer and easier to use process_input_buffer
if you only want to change one line at a time. You can use status.input_ptr
to only affect lines from specific files: (I fixed the pattern in the process)
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")
Even if this is much less dangerous, I would still recommend looking for ways to archive your goals without rewriting input lines.
$$
and$
symbols "on the fly", i.e., without writing its modified input stream back to file?