在普通 TeX 循环内匹配数字符号

在普通 TeX 循环内匹配数字符号

为了从我想从文件输入到 TeX 的代码中删除注释,我使用了以下循环

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

代码在没有循环的情况下也可以工作,但是在循环内部它会给我一个错误消息,因为#表示我想将参数传递给\loop命令,但这不是我想要的。

我的第一个想法当然是#使用\char"23或进行转义\#,但这两个表达式与井号字符不匹配,并且\expandafter在它前面放置一个似乎并没有改变这一点。

你们中是否有人知道一种可以转义数字符号但仍允许将其与输入字符匹配的方法?

答案1

您必须隐藏#的文本\loop,因为它确实

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

一种方法如下

\documentclass{article}
\edef\hashmark{\string#}
\def\getfirst#1#2\getfirst{\string#1}
\newread\myread
\begin{document}
\openin\myread=mysrcfile.txt
  \newcount\linecount
  \global\linecount1
  \loop
    \unless\ifeof\myread
    \read\myread to \myinput
    \if\hashmark\expandafter\getfirst\detokenize\expandafter{\myinput}\getfirst                      
    \else
      \expandafter\myinput
    \fi
    \global\advance\linecount1
  \repeat
\closein\myread
\end{document}

分隔符,而不是\relax不应\getfirst出现在输入文件中的分隔符。

这需要 e-TeX;如果没有 e-TeX,您可以更改类别代码#

\long\def\getfirst#1#2\getfirst{#1}
\openin\myread=mysrcfile.txt
  \newcount\linecount
  \global\linecount1
  \begingroup\catcode`#=12
  \loop
    \unless\ifeof\myread
    \read\myread to \myinput
    \if\hashmark\expandafter\getfirst\myinput\getfirst
    \else
      \expandafter\myinput
    \fi
    \global\advance\linecount1
  \repeat
  \endgroup
\closein\myread

\long是为了防止输入文件中出现空行。


使用 LaTeX3 宏的可能实现;处理起来总是相当困难#

\documentclass{article}
\usepackage{xparse,l3str}
\ExplSyntaxOn
% the user level command
\NewDocumentCommand{\readremovingcomments}{m}
 {
  \penguin_read_nocomments:n { #1 }
 }
% the low level command
\cs_new_protected:Npn \penguin_read_nocomments:n #1
 {
  % 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}
\readremovingcomments{mysrcfile.txt}
\end{document}

答案2

您可以通过设置宏来测试参数标记,例如

\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=#%

关键在于定义\parameter@token不是#但使用时却是这样的。这导致了类似

\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}
\newread\myread
\openin\myread=mysrcfile.txt %
\loop
  \unless\ifeof\myread
    \read\myread to \myinput
    \expandafter\expandafter\expandafter\if@parameter@token@TF
      \expandafter\getfirst\myinput\relax
      {}
      {\myinput}%
  \repeat
\immediate\closeout\myread
\end{document}

另一方面,您可以将其#作为“其他”字符来读取并避免此问题,或者确实\readline按照正在使用的 e-TeX 来使用。

相关内容