我正在定义一个包装环境,filecontents
以便我可以修改它的行为。
大多数测试用例都运行良好。例如,我定义了一个环境testenv
,它接受一个强制参数并将其值写入控制台:
\newenvironment{testenv}[1]{%
\typeout{Argument = #1}%
\filec@ntents{\jobname.pfc}%
}{}
所以当我打电话时
\begin{testenv}{hello}
hi
\end{testenv}
LaTeX 打印Argument = hello
到控制台并写入一个名为的文件\jobname.pfc
,其中包含
hi
这适用于无参数环境和强制参数环境。对于带有可选参数的环境,只要可选参数存在,它就会起作用,否则会失败。
下面的代码说明了所有的情况。最后一个会抛出一个Missing \begin{document}
错误:
\documentclass{book}
\usepackage{filecontents}
\makeatletter
\newenvironment{testenv}{%
\filec@ntents{\jobname.pfc}%
}{}
% The environment works without arguments
\begin{testenv}
hi
\end{testenv}
\renewenvironment{testenv}[1]{%
\typeout{Argument = #1}%
\filec@ntents{\jobname.pfc}%
}{}
% and with mandatory arguments
\begin{testenv}{hello}
hi
\end{testenv}
\renewenvironment{testenv}[1][abcde]{%
\typeout{Argument = #1}%
\filec@ntents{\jobname.pfc}%
}{}
% and it works with optional arguments
% only if the argument is given
\begin{testenv}[hello]
hi
\end{testenv}
% otherwise it fails :/
\begin{testenv}
hi
\end{testenv}
\begin{document}
\end{document}
该参数的实际用途是在环境内容之后排版一些文本,因此 catcode 并不那么重要。
答案1
在您的环境处理任何参数之前,请确保文件内容环境使用的 catcode-régime 有效。
在 filecontents-catcode-régime 下可以处理可选参数,因为应用该régime 不会改变 的 catcode [
。
根据您希望在实际应用程序中对可选参数执行的操作,您可能需要在正常的 catcode 机制下对其进行重新标记。
(对于简单来说,\typeout
这不是必需的。)
\scantokens
这可以通过 eTeX 扩展来完成。
如果 eTeX 扩展不可用,则可以通过将其未扩展写入临时文件并通过\input
(TeX) / \@@input
(LaTeX2e) 使 (La)TeX 读取/标记该临时文件来完成。
\documentclass{book}
\usepackage{filecontents}
\makeatletter
\newcommand\setcatcodesoffilecontents{%
\let\do\@makeother\dospecials
%
\count0=128\relax
\loop %
\catcode\count0=11\relax
\advance\count0 by 1\relax
\ifnum\count0<256 %
\repeat
%
\catcode`\^^L\active
\catcode`\^^I\active
\catcode`\^^M\active
}%
\newenvironment{testenv}{%
\begingroup
\setcatcodesoffilecontents
\innertestenv
}{}%
\newcommand\innertestenv[1][abcde]{%
\endgroup
\typeout{Argument = #1}%
\@tempswatrue %<-As file-preamble write the phrase
% %% LaTeX2e file `\jobname.pfc'
% %% generated by the `testenv' environment
% %% from source `test' on 2018/06/30.
%\@tempswafalse %<-Don't write a file-preamble.
\filec@ntents{\jobname.pfc}%
}%
% With optional argument:
%
%\begin{testenv}[hello]
% hi
%\end{testenv}
% Without optional argument:
%
\begin{testenv}
hi
\end{testenv}
\begin{document}
\end{document}
答案2
使用或类似方法收集材料时filecontents
会使用逐字方法。这意味着任何标记化都可能(并且会)导致问题。您看到的问题是,当查找可选的 时[
,TeX 会标记直到 为止(包括) h
。具体来说,这意味着行尾已“消失”。收集标记依赖于抓取到行尾(^^M
),因此我们在这里“丢失”h
了 ,\everypar
从而触发错误。
在 中也出现了类似情况beamer
,即采取额外步骤来“确保”行开始后的第一个标记的安全。但是,这充其量也有些脆弱,我不会依赖它。