输入:跳过 n 行

输入:跳过 n 行

我正在尝试插入另一个文件的内容,同时可选择跳过前 n 行。我可以控制插入的内容,我当前的解决方案只是将前 n 行包装在顺序命名的宏中,我可以将其重新定义为无,从而抑制输入。这让我觉得相当丑陋。

似乎inputinclude无法跳过行。有像这样的包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在第一行包含一个注释(如问题所示),因此第一个跳过的行是输出中未显示的注释行。

相关内容