conditionals – Testing Lines Read from External File in LaTeX: Best Practices

conditionals

I am trying to read some data from an external file and perform specific actions based on the contents of a given line.

Below is my attempt to test a read line using \ifx – it does not work. I've also tried using \ifthenelse from the ifthen package and some of the generic tests from etoolbox. As all my attempts has failed, I now have two questions:

  1. How do I perform a test to see if data read from an external file matches a specified sting?
  2. How should I debug to work out why my test fails? Based on the typeset output from the MWE below, Line with bar read from the external file does seem to match \linetomatch?

As the \usepackage statements in the preambel indicates, I would like the code to work with both LuaLaTeX and pdfLaTeX (opening the file with io.open in a \directlua block works and I can do the testing with Lua in LuaLaTeX. However, I would prefer a version working in pdfLaTeX too).

\documentclass{article}
\usepackage{fontspec}
%\usepackage[T1]{fontenc}
%\usepackage[utf8]{inputenc}

\usepackage{filecontents}
\begin{filecontents*}{datafile.txt}
Line with foo
Line with bar
Line with baz
\end{filecontents*}

\makeatletter
\newread\myread
\def\loaddata#1{%
    \edef\linetomatch{Line with bar}%
    \openin\myread=#1
    \@whilesw\unless\ifeof\myread\fi{%
        \readline\myread to \dataline%
        \noindent"\linetomatch"
        \ifx\dataline\linetomatch\relax
            equals 
        \else
            does not equal
        \fi
        "\dataline"\par
    }%
    \closein\myread
}%
\makeatother

\begin{document}

\loaddata{datafile.txt}

\end{document}

Best Answer

There are two glitches in your macros.

  1. You use \readline instead of \read
  2. You don't disable the \endlinechar

The \readline instruction puts into \dataline a string of category code 12 tokens (10 for spaces). Instead your \linetomatch macro has category code 11 tokens in its replacement text. So it's better to use \read, in general.

TeX always appends the \endlinechar byte to the end of input lines (usually byte 13), unless this value is out of range (–1 is good for disabling it).

Less serious is the empty line (with possibly only the \endlinechar in it) that's implicitly added at the end of all input files.

\makeatletter
\newread\myread
\def\loaddata#1{%
    \def\linetomatch{Line with bar}% \edef is not required
    \openin\myread=#1
    \begingroup\endlinechar=-1
    \@whilesw\unless\ifeof\myread\fi{%
        \read\myread to \dataline
        \noindent"\linetomatch"
        \ifx\dataline\linetomatch\relax
            equals
        \else
            does not equal
        \fi
        "\dataline"\par
    }%
    \endgroup
    \closein\myread
}%
\makeatother

enter image description here

Related Question