Input: skip n lines

inputluatextex-core

I am trying to insert content from another file whilst optionally skipping the first n lines. I have control over the inserted content, and my current solution is simply to wrap the first n lines in sequentially named macros which I can redefine to nothing, thereby suppressing the input. This strikes me as rather ugly.

It seems input and include are not capable of skipping lines. There are packages like standalone, but I'm not trying to remove content before a begin{document}, I'm just trying to skip lines in a verse environment.

Specifically my imported files look like this:

% lines.tex
line 1\\
line 2\\
line 3\\

Note that 'source lines' and 'output lines' are identical in this case, as exactly one output line ending in \\ is found on one input line. I don't really mind which I end up working on.

And I'm looking to do something like this:

\begin{verse}
\includelines[2]{lines} % skips first 2 lines
\end{verse}

I thought it would be relatively straightforward to iterate over the included content linewise, but having not found anything it seems this isn't really done.

If I am simply thinking in the wrong paradigm and the 'correct' way is to do as I am currently doing (wrap lines in macros which can be redefined later and thus not output anything) I don't mind sticking with that.

I am using LuaLaTeX anyhow, so I'm open to solutions using Lua.

Current Solution

Currently I do this, but it clutters up both the document and the imported document. I could avoid cluttering the document by wrapping the \lets in an environment, and using a number-to-word routine together with \csname. But I was hoping for a solution which didn't requite cluttering up the included document.

\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}

Best Answer

Here I use readarray (which loads the forloop package). The optional argument is the line to begin on rather than skip. If you really prefer it the other way, let me know.

Two items to note (hat tip Marcel): 1) make sure you have the [2021-09-17] version of the readarray package, which will, with the setting \ignoreblankreadarrayrecordstrue, properly skip over fully commented lines when tabulating records from the input; 2) if a braced group spans more than a single line of the input file, the record that contains the group will contain the whole group, meaning that such a record will be seen to span several lines of input.

\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}

enter image description here

Related Question