In order to strip comments from code I would like to input from a file into TeX, I am using the following loop

\documentclass{article}
\def\getfirst#1#2\relax{#1}
\begin{document}
\openin1=mysrcfile.txt
\newcount\linecount
\global\linecount1
\loop
\unless\ifeof1
\if\expandafter\getfirst\expandafter\myinput\relax #  % Here's the problem
\relax
\else
\myinput
\fi
\repeat
\closein1
\end{document}


The code works without the loop, but inside the loop it gives me an error message, because # indicates I would like to hand on parameters to the \loop command, which is not what I want.

My first idea was of course escaping # using \char"23 or \#, but theses two expressions don't match the hash character and placing an \expandafter in front of it doesn't seem to change that.

Does anyone of you know about a way which escapes the number sign, but still allows for matching it to input chars?

-
Do you need to read the file such that # is a parameter token, or is it acceptable to read with an alternative catcode? –  Joseph Wright Dec 25 '12 at 11:28
My only suggestion is to perhaps do a global replace inside the input file, replacing '#' for something like '<REM>', which will then not be subject to the same issues. –  Nicholas Hamilton Dec 25 '12 at 12:34

You have to hide # from the text of \loop, since it does

\def\iterate{<text up to \repeat>}


A way can be as follows

\documentclass{article}
\edef\hashmark{\string#}
\def\getfirst#1#2\getfirst{\string#1}
\begin{document}
\newcount\linecount
\global\linecount1
\loop
\if\hashmark\expandafter\getfirst\detokenize\expandafter{\myinput}\getfirst
\else
\expandafter\myinput
\fi
\repeat
\end{document}


The delimiter, instead of \relax is \getfirst which should not appear in the input file.

This requires e-TeX; without e-TeX you can change the category code of #:

\long\def\getfirst#1#2\getfirst{#1}
\newcount\linecount
\global\linecount1
\begingroup\catcode#=12
\loop
\if\hashmark\expandafter\getfirst\myinput\getfirst
\else
\expandafter\myinput
\fi
\repeat
\endgroup


The \long is to protect against empty lines in the input file.

A possible implementation with LaTeX3 macros; it's always quite hard to deal with #:

\documentclass{article}
\usepackage{xparse,l3str}
\ExplSyntaxOn
% the user level command
{
}
% the low level command
{
% open the input stream
\ior_open:Nn \l_penguin_source_ior { #1 }
% read one line at a time
\ior_map_inline:Nn \l_penguin_source_ior
{
% extract the first token from the input line (after stringifying it)
\tl_set:Nx \l__penguin_temp_tl { \tl_head:f { \tl_to_str:n { ##1 } } }
% check whether the first token is #; if not, print the line
\tl_if_eq:NNF \l__penguin_temp_tl \c_hash_str { ##1 }
}
\ior_close:N \l_penguin_source_ior
}
\tl_new:N \l__penguin_temp_tl
\ior_new:N \l_penguin_source_ior
\ExplSyntaxOff

\begin{document}
\end{document}

-

You can test for a parameter token by setting up a macro such as

\let\parameter@token=\relax
\long\def\if@parameter@token@TF#1{%
\ifcat\noexpand#1\parameter@token
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
}
\let\parameter@token=#%


where the key is that at the point of definition \parameter@token is not a #, but when used it is. That leads to something like

\documentclass{article}
\long\def\getfirst#1#2\relax{#1}
\makeatletter
\let\parameter@token=\relax
\long\def\if@parameter@token@TF#1{%
\ifcat\noexpand#1\parameter@token
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
}
\let\parameter@token=#%
\begin{document}
\loop

On the other hand, you could just read with # as an 'other' character and avoid the issue, or indeed use \readline as e-TeX is in use.
Reading #` with another character might be a very elegant solution to the problem, but although using LaTeX for quite a while now, I don't know how to do this in plain TeX. Could you point out a bit further on how to do this? –  Penguin Nurse Dec 25 '12 at 16:38