Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

What is the easiest technique to get the n-th line from a input file called input and pass it on to a macro called \process. Please note that I'm not asking about outputing the n-th line verbatim but about catching the line and passing it on to the macro. The macro \process is defined as follows:

\def\process#1\endprocess{%
    % process #1
}

The n-th line of the input file should be passed as the argument #1 to the macro \process.

share|improve this question
    
@werner The external-files tag is good. Thanks for providing it. The input tag, which I added in a related thread, was removed twice:-) –  Marc van Dongen Jan 4 '12 at 23:41
    
Now that you mention it, input seems to be inappropriate here since you're not actually using (or requesting the use of) \input, but you're processing part of an external-file. –  Werner Jan 4 '12 at 23:44
    
@werner I agree that input isn't so good. –  Marc van Dongen Jan 4 '12 at 23:47
add comment

1 Answer

up vote 5 down vote accepted
\makeatletter
\newread\dongen@in
\newcommand{\dongenprocess}[2]{% #1=file name, #2=line to read
  \begingroup\endlinechar=\m@ne
  \openin\dongen@in=#1\relax
  \count@=\z@
  \loop\ifnum\count@<#2\relax
    \ifeof\dongen@in
      \ERROR
    \else
      \read\dongen@in to \@tempa
    \fi
    \advance\count@\@ne
  \repeat
  \ifx\@tempa\@empty\ERROR\fi
  \closein\dongen@in
  \expandafter\endgroup
  \expandafter\process\@tempa\endprocess
}
\makeatother

If you try to get past the end of the file you'll get some errors; of course you can define \ERROR as you wish, for example providing a fallback. I assume that lines are not empty. The second \ERROR corresponds to the empty line that TeX implicitly assumes at the end of a file.

Basically, I do a loop reading one line at a time until reaching the desired one. Then \@tempa (expanded) is passed to \process.

Call it as

\dongenprocess{dongen.dat}{2}

to read the second line.

Here is a possible LaTeX3 implementation:

\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\dongenprocess}{mm}
  {
   \group_begin: \tex_endlinechar:D \c_minus_one
   \ior_open:Nn \l_dongen_read_s { #1 }
   \prg_replicate:nn {#2}
     {
      \ior_if_eof:NTF \l_dongen_read_s
       { \dongen_error: }
       { \ior_to:NN \l_dongen_read_s \l_dongen_read_tl }
     }
   \ior_close:N \l_dongen_read_s
   \tl_if_empty:NT \l_dongen_read_tl { \dongen_error: }
   \exp_args:NNo \group_end: \dongen_process:n { \l_dongen_read_tl }
  }

\ior_new:N \l_dongen_read_s
\tl_new:N \l_dongen_read_tl
\cs_new:Npn \dongen_process:n #1 { \process#1\endprocess }
\cs_new:Npn \dongen_error: { \tl_set:Nn \l_dongen_read_tl { INEXISTENT~LINE } }
\ExplSyntaxOff

EDIT: alternative version of \dongenprocess that trims spaces around the input read from the file

\NewDocumentCommand{\dongenprocess}{mm}
  {
   \group_begin:
   \ior_open:Nn \l_dongen_read_s { #1 }
   \prg_replicate:nn {#2}
     { 
      \ior_if_eof:NTF \l_dongen_read_s 
       { \dongen_error: }
       { \ior_to:NN \l_dongen_read_s \l_dongen_read_tl }
     }
   \ior_close:N \l_dongen_read_s
   \tl_trim_spaces:N \l_dongen_read_tl
   \tl_if_in:NnT \l_dongen_read_tl { \par } { \dongen_error: }
   \exp_args:NNo \group_end: \dongen_process:n { \l_dongen_read_tl }
  }
share|improve this answer
    
Thanks. Looks like an easy enough solution for a file processing toolkit. I've uppped your score but I'll wait a bit longer before I choose the/some best solution. –  Marc van Dongen Jan 4 '12 at 23:43
    
I like the elegance of the naming convention of the macros: \dongenprocess, \l_dongen_read_tl, ... –  Marc van Dongen Jan 5 '12 at 2:24
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.