12

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}

1 Answer 1

11

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

2
  • Thank you for the explanation and the working code! What is the route I should have followed to arrive at this solution? Is this just something "one has to know" or RTFM, or are there some systematic way of debugging - inspection of the typeset result did not provide many hints. Commented Apr 29, 2013 at 14:33
  • @MartinHeller Reading and writing to files is not so common a subject. TeX by Topic has a good deal about these functions (texdoc texbytopic). Also \readline is a new primitive introduced by pdftex, while \read is the original Knuth primitive.
    – egreg
    Commented Apr 29, 2013 at 14:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .