我正在尝试插入另一个文件的内容,同时可选择跳过前 n 行。我可以控制插入的内容,我当前的解决方案只是将前 n 行包装在顺序命名的宏中,我可以将其重新定义为无,从而抑制输入。这让我觉得相当丑陋。
似乎input
和include
无法跳过行。有像这样的包standalone
,但我并不是想删除之前的内容begin{document}
,我只是试图在verse
环境中跳过行。
具体来说,我导入的文件如下所示:
% lines.tex
line 1\\
line 2\\
line 3\\
请注意,在这种情况下,“源行”和“输出行”是相同的,因为\\
在一个输入行上恰好找到一个以 结尾的输出行。我并不介意最终处理哪一个。
我正在寻找做这样的事情:
\begin{verse}
\includelines[2]{lines} % skips first 2 lines
\end{verse}
我认为逐行迭代所包含的内容相对简单,但是没有发现任何东西,似乎这并没有真正完成。
如果我只是以错误的范式思考,而“正确”的方式就是按照我现在的方式去做(在宏中换行,这些宏可以稍后重新定义,因此不会输出任何内容),我不介意坚持这样做。
我正在使用LuaLaTeX
,所以我愿意接受使用 Lua 的解决方案。
当前解决方案
目前我这样做,但它会使文档和导入的文档都变得混乱。我可以通过将 s 包装\let
在环境中,并使用数字到单词例程以及\csname
避免文档混乱。但我希望找到一个不会导致文档混乱的解决方案包括文档。
\documentclass{article}
\begin{document}
% I define a long list of these, more than I will ever need
\def\printLine#1{#1}
\let\lineOne\printLine
\let\lineTwo\printLine
\let\lineThree\printLine
\let\lineFour\printLine
\def\dummy#1{}
\begin{verse}
\let\lineOne\dummy
\let\lineTwo\dummy
% In reality we have an \input statement here
\lineOne{line1\\}
\lineTwo{line2\\}
\lineThree{line3\\}
\lineFour{line4\\}
\let\LineOne\printLine
\let\LineTwo\printLine
\end{verse}
\end{document}
答案1
这里我使用readarray
(加载forloop
包)。可选参数是要从哪行开始而不是跳过。如果您确实喜欢其他方式,请告诉我。
需要注意的两点(提示 Marcel):1)确保你拥有的[2021-09-17]
软件包版本readarray
与设置一致\ignoreblankreadarrayrecordstrue
,在对输入记录进行制表时,可以正确跳过完全注释的行;2)如果括号组跨越输入文件中的多行,则记录包含该组的将包含所有的组,这意味着记录将会被视为跨越多行输入。
\begin{filecontents*}[overwrite]{lines.tex}
%
Line 1
Line 2
Line 3
% A COMMENT IN THE FILE
Line 4
\end{filecontents*}
\documentclass{article}
\usepackage{readarray}[2021-09-17]
\ignoreblankreadarrayrecordstrue
\newcounter{lino}
\newcommand\includelines[2][1]{%
\readrecordarray{#2}\linearray
\forloop{lino}{#1}{\thelino < \numexpr1+\linearrayROWS}
{\ifnum\value{lino}>#1\\\fi
\linearray[\thelino]}
}
\begin{document}
\includelines{lines.tex}
\includelines[2]{lines.tex}
\includelines[3]{lines.tex}
\includelines[4]{lines.tex}
\end{document}
答案2
这可以用纯 TeX 代码完成,但这里有一个 Lua 解决方案(解释以注释形式添加):
\documentclass{article}
\newluafunction\skiplines
\directlua{
% Some boilerplate
local func = \the\allocationnumber
token.set_lua('skiplines', func, 'protected')
local input = token.create'input'
lua.get_functions_table()[func] = function()
% Read the number of lines to be skipped
local count = token.scan_int()
% Add a callback to change how TeX files are opened
luatexbase.add_to_callback('open_read_file', function(name)
% We only want to affect a single file, so we should remove the callback again.
%% luatexbase.remove_from_callback('open_read_file', 'skip_input_lines')
% But we delay this until TeX actually tries to read from the file since LaTeX might open the file multiple times.
% Now open the file for reading
local f = io.open(name, 'r')
% If the file can't be opened we return nothing.
if not f then return end
% Remember if we are reading the first line
local first = true
% And return the reader table
return {
reader = function()
% If TeX is trying to read the first line, unregister the callback and skip the first lines
if first then
luatexbase.remove_from_callback('open_read_file', 'skip_input_lines')
for i = 1, count do f:read'l' end
first = false
end
% Then just read a line and report it to TeX
return f:read'l'
end,
% Remember to close the file when we are done with it
close = function() return f:close() end,
}
end, 'skip_input_lines')
% Finally add a \input to read the filename and initiate the reading.
token.put_next(input)
end
% This code contains a small bug: If the file does not exists,
% luatexbase.remove_from_callback will not be called and the
% next time LaTeX tries to read a file the first lines get lost.
% Avoiding this is complicated since LaTeX sometimes tries to
% open non-existing files before opening the real one, so we can't
% run remove_from_callback if the file doesn't exists.
% It's not a big issue though since \input with a non existing filename is an error anyway,
% So the issue only occurs if the compilation fails anyway. If a user chooses to ignore the
% error message, they shouldn't expect sensible behavior afterwards.
}
\begin{document}
\begin{verse}
Skip 0 lines:\\
\skiplines 0{lines}
after\\
\end{verse}
\begin{verse}
Skip 1 lines:\\
\skiplines 1{lines}
after\\
\end{verse}
\begin{verse}
Skip 2 lines:\\
\skiplines 2{lines}
after\\
\end{verse}
\begin{verse}
Skip 3 lines:\\
\skiplines 3{lines}
after\\
\end{verse}
\begin{verse}
Skip 4 lines:\\
\skiplines 4{lines}
after\\
\end{verse}
\end{document}
也许您想知道为什么它看起来比预期少跳过了一行:我的版本lines.tex
在第一行包含一个注释(如问题所示),因此第一个跳过的行是输出中未显示的注释行。