我发现了 catchfile这里 现在我想了解这个包是如何工作的。下面是一些使用\foreach
或的测试\@for
\documentclass{article}
\usepackage{filecontents,catchfile,pgffor}
\begin{document}
\def\mylist{1,2,3,4}
Test 1:\foreach \i in \mylist {\hspace{\i cm}\i}
\begin{filecontents*}{mylist.dat}
1,2,3,4
\end{filecontents*}
\CatchFileDef{\tempa}{mylist.dat}{}%
Test 2:\foreach \i in \tempa{\hspace{\i cm}\i}
\makeatletter
Test 3:\@for\i:=\tempa\do{\hspace{\i cm}\i}
\def\tempb{\@@input mylist.dat }
% I know this is not the right way but I always find it difficult to explain
Test 4: this is the content : \tempb
% \foreach \i in \tempb
% {\hspace{\i cm}\i} %
Test 5:\@for\i:=\tempb\do{\hspace{\i cm}\i}
\begin{filecontents*}{myfile.dat}
\def\tempc{1,2,3,4}
\end{filecontents*}
\input{myfile.dat}
% last try ! and it works
Test 6:\foreach \i in \tempc{\hspace{\i cm}\i}
\end{document}
A) 测试 4 不起作用。但为什么测试 2 可以\CatchFileDef
工作?对这类问题有一个清晰的解释会很有趣!
B)现在为什么测试 6 有效?
答案1
的定义\CatchFileEdef
可以简化为
\newcommand\easyCatchFileEdef[3]{%
\begingroup\everyeof{\noexpand}%
#3\relax
\xdef\@temp{\@@input #2\space}%
\endgroup
\let#1\@temp
}
但 Heiko Oberdiek 还添加了许多检查。 是\everyeof{\noexpand}
必要的,以消除 TeX 添加到其输入的每个文件中的隐式空行。\@@input
命令是原始的\input
,它是可扩展的(使用空扩展); 最后一个\space
用于应对 TeX 关于 (原始)的惯例\input
:查找并忽略空格。 第三个参数用于在输入文件时添加设置,例如\endlinedchar
。
一切都\xdef
扩展了(它的\global\edef
),但只是#1
在本地定义。
更复杂的是\CatchFileDef
,因为人们只想扩展\@@input
而不是实际输入的内容。未删节的版本是
\makeatletter
\def\easyCatchFileDef#1#2#3{%
\begingroup\everyeof\expandafter{\CatchFileEOF\expandafter\CatchFileFinish\noexpand}%
\expandafter\long\expandafter\def\expandafter\CatchFileDo
\expandafter##\expandafter1\CatchFileEOF{\edef\CatchFileFinish{\endgroup
\unexpanded{\edef#1{\unexpanded{##1}}}}}%
#3\relax
\expandafter\CatchFileDo\@@input #2\relax}
\begingroup
\lccode65=64 % lowercase('A') = '@'
\lccode66=64 % lowercase('B') = '@'
\catcode65=8 % catcode('A') = subscript
\catcode66=3 % catcode('B') = math shift
\lowercase{\endgroup
\def\CatchFileEOF{AB}%
}
\makeatother
令牌\CatchFileEOF
有两个@
,第一个是 catcode 8,第二个是 catcode 3(任何人都不应该在文件中拥有它),本质上,执行的\easyCatchFiledef{\my}{file}{}
是
\def\CatchFileDo#1@@{%
\edef\CatchFileFinish{\endgroup
\unexpanded{\edef\my{\unexpanded{#1}}}}}%
\CatchFileDo<contents of file.tex>@@\CatchFileFinish
因为\expandafter
之前的\CatchfileDo
会扩展\@@input
并显示 TeX 的内容file.tex
。上面的行@@
代表\CatchFileEOF
特殊的分隔符标记。
实际上包含了当前版本 e-TeX 中不存在的catchfile.sty
情况的代码,但这与讨论无关。Heiko 一如既往地做得很聪明。\unexpanded
答案2
据我所知,该宏可以通过一些 e-TeX 技巧来工作。如果没有这个技巧,如果您在可扩展上下文(如)中\CatchFileDef
使用 TeX \input
(在 LaTeX 中重命名为),则会收到错误。在这种情况下,会触发类似“检测到文件结尾时...”的错误。\@@input
\edef
您的测试 4 不起作用,因为您在这里使用了\@@input
简单的测试\def
:
\def\tempb{\@@input mylist.dat }
\foreach \i in \tempb {..}
请\tempb
注意不是包含文件内容,而是\@@input
包含文件名的宏,这对 来说并不好\foreach
。这就像使用\foreach \i in {\@@input mylist.dat} {..}
,这没有多大意义。您需要\edef
改为使用 来扩展 ,\@@input
以便\tempb
先包含文件内容。但是,如上所述,这不起作用。
\tempc
测试 6 之所以有效,是因为您直接在输入文件中定义使用逗号分隔内容的宏,这在这里没有任何区别。测试 5 对您有用吗?这对我来说会更令人惊讶。