我想制作一个宏来导入包含该宏的输入文件所在的目录中的所有 TeX 输入文件。读取外部文件时,TeX 在最后一次迭代后附加一个空行。
在下面的代码中,我使用了一个糟糕的算法,因为有两个循环。第一个用于查找整个文件,另一个用于执行主要工作。
\documentclass{article}
\usepackage{listings}
\lstset{language={[LaTeX]TeX},breaklines=true}
\def\X
{%
\immediate\write18{cmd /c dir /b *.tex > \jobname-temp.txt}%
\newread\myfile
\openin\myfile=\jobname-temp.txt
\newcount\counter
\counter=0
\loop
\unless\ifeof\myfile
\read\myfile to\mydata
\advance \counter by 1
\repeat
\closein\myfile
\openin\myfile=\jobname-temp.txt
\advance \counter by -1
\loop
\ifnum \counter > 0
\read\myfile to\mydata
\section\mydata
\lstinputlisting{"\mydata"}\newpage
\advance \counter by -1
\repeat
\closein\myfile
}
\begin{document}
\X
\end{document}
我想使用单循环来提高性能。
如何在逐行读取外部文件时检测 TeX 插入的空白行?
答案1
读完该行后,只需再次检查 EOF。
最低限度工作示例:
\documentclass{article}
\usepackage{filecontents}
\begin{filecontents*}{\jobname.dat}
first
second
third
fourth
\end{filecontents*}
\newread\myfile
\newcommand*\readfile{%
\immediate\openin\myfile=\jobname.dat\relax
\loop\unless\ifeof\myfile
\read\myfile to\mydata
\ifeof\myfile\else
\section\mydata
\fi
\repeat
\immediate\closein\myfile
}
\begin{document}
\readfile
\end{document}
如果您想避免双重 EOF 检查,请使用如下递归宏:
\newcommand*\readfile{%
\immediate\openin\myfile=\jobname.dat\relax
\ifeof\myfile\else% file exists?
\expandafter\readoneline
\fi
\immediate\closein\myfile
}
\def\readoneline{%
\read\myfile to\mydata
\ifeof\myfile\else
\section\mydata
% ...
\expandafter\readoneline
\fi
}
\par
如果(原始)外部行以换行符结尾(2x 换行符 => \par
,一如既往),则添加的空行将添加一个。因此\mydata
将包含\par
(如果您像我之前告诉过的那样使用\show
它来调试它,您就会知道)。您可以使用以下方法测试这一点:
\def\lastline{\par}
%...
\ifx\mydata\lastline
%...
\fi
当然,这个测试对于输入文件中的任何其他隐式或显式行也适用\par
,因此测试 EOF 实际上通常更安全,但在这里您无论如何都想避免所有这样的输入行(并不是说它们会出现在您的示例中的任何其他地方)。
答案2
我改进了 Martin 的算法。我不使用递归方法,因为如果文件太多,它可能会因堆栈溢出(没有 .com)而损坏。我也不针对 EOF 使用双重测试。:-)
\def\X
{%
\immediate\write18{cmd /c dir /b *.txt > \jobname-temp.dat}%
\newread\myfile
\openin\myfile=\jobname-temp.dat\relax
\loop
\read\myfile to \mydata
\unless\ifeof\myfile
\section\mydata
\lstinputlisting{"\mydata"}\newpage
\repeat
\closein\myfile
}