命令 \env 已定义

命令 \env 已定义

这是如何忽略文档环境中的所有内容?

下面的代码旨在提取发生的标记的值 \begin{document}。出于某种原因,宏存在一个\DisablePreamble我无法弄清楚的问题。令人惊讶的是,它似乎在我的实际使用案例中一直有效,但当我尝试进行 MWE(试图重现另一个问题)时却不起作用。

Filegoo.tex是一个极其简化的测试用例,因为它没有任何前导码,所以不需要调用\DisablePreamble——而且这是有效的。但是,在我的实际用例中(如foo.tex),有一个前导码和一个document需要忽略的完整环境,因此需要\DisablePreamble

下面的例子产生:

MyToken=goobar

MyToken=goobar

因为该\ExtractMyTokenA行被注释掉了,但是\ExtractMyTokenA注释掉了应该收益率(注意第二行的变化):

MyToken=goobar

MyToken=foobar

当对 的调用\ExtractMyTokenA取消注释时,结果如下:

./TeX-SE.tex:75: LaTeX Error: Command \env already defined.
            Or name \end... illegal, see p.192 of the manual.

参考:

笔记:

  • 要使给定的 MWE 失败,您需要取消注释该\ExtractMyTokenA行。
  • 实际问题在于\DisablePreamble,但这个 MWE 看起来比实际情况更复杂,因为:
    1. 我有两个临时文件foo.texgoo.tex测试用例。
    2. \ExtractMyTokenA\ExtractMyTokenA几乎完全相同:一次调用\DisablePreamble,另一个不调用。

代码:

\documentclass{article}
\usepackage{environ}

%  This file is ONLY needed once we get past the error message.
%\usepackage{filecontents}% Comment out so as to NOT overwrite foo.tex and goo.tex.
\begin{filecontents*}{foo.tex}
    \documentclass{standalone}
    \usepackage{MyStandardPackages}
    \input{MyStandardSetup}

    \MyToken={foobar}%   <----- Only this line should be executed. ALL other lines in foo.tex are to be ignored.

    \begin{document}
       lots of text here

       \SetSomeVarable{\SomeVar}{Some Value}
       
       \begin{SomeEnvironment}
           lots more stuff here as well
       \end{SomeEnvironment}
    \end{document}
\end{filecontents*}

% This file does not have a preamble so won't need a call to "\DisablePreamble"
\begin{filecontents*}{goo.tex}
    \MyToken={goobar}%   <----- Only this line should be executed. ALL other lines in foo.tex are to be ignored.
\end{filecontents*}

%% ------------------------------
%% Problem is in here somewhere!!  Shows up once we uncomment "\ExtractMyToken{foo}" below.
\newcommand{\DisablePreamble}{%
        \renewcommand{\documentclass}[2][]{}%  remove def'n of \documentclass
        %% https://tex.stackexchange.com/questions/165258/how-to-ignore-everything-in-the-document-environment
        \providecommand{\env@document@save@env}{}% To keep environ happy
        \providecommand{\env@document@process}{}%
        \RenewEnviron{document}{}% Ignore everything within the "document" environment.
        \renewcommand{\usepackage}[2][]{}% 
}%

\newtoks{\MyToken}
\newcommand{\FileWithPath}{}%
\newcommand{\ExtractMyTokenA}[1]{% Same as \ExtractMyTokenB, except invokes "\DisablePreamble" 
    % #1 = File Name with path
    \begingroup%
        \DisablePreamble%
        % -----------
        \let\OldInput\input%         Need to redefine \input as the file being read uses
        \renewcommand*{\input}[1]{}% \input before \begin{document}.
        % -----------
        \edef\FileWithPath{#1}%
        \OldInput{\FileWithPath}%
        \global\MyToken=\expandafter{\the\MyToken}
    \endgroup%
}%

\newcommand{\ExtractMyTokenB}[1]{% Same as \ExtractMyTokenA, except "\DisablePreamble" is commented.
    % #1 = File Name with path
    \begingroup%
        %\DisablePreamble% This works great for the case where there is no preamble.
        % -----------
        \let\OldInput\input%         Need to redefine \input as the file being read uses
        \renewcommand*{\input}[1]{}% \input before \begin{document}.
        % -----------
        \edef\FileWithPath{#1}%
        \OldInput{\FileWithPath}%
        \global\MyToken=\expandafter{\the\MyToken}
    \endgroup%
}%


\begin{document}
    \ExtractMyTokenB{goo}%  <----- This does not invoke \DisablePreamble, and works 
    MyToken=\the\MyToken\par
    % ------------
    %\ExtractMyTokenA{foo}%   <----- This invokes \DisablePreamble, which fails 
    MyToken=\the\MyToken\par
\end{document}

答案1

 \providecommand{\env@document@save@env}{}% To keep environ happy

\env@document@save@env如果这样定义的话会更开心\env:-)

\documentclass{article}
\usepackage{environ}

%  This file is ONLY needed once we get past the error message.
%\usepackage{filecontents}% Comment out so as to NOT overwrite foo.tex and goo.tex.
\begin{filecontents*}{foo.tex}
    \documentclass{standalone}
    \usepackage{MyStandardPackages}
    \input{MyStandardSetup}

    \MyToken={foobar}%   <----- Only this line should be executed. ALL other lines in foo.tex are to be ignored.

    \begin{document}
       lots of text here

       \SetSomeVarable{\SomeVar}{Some Value}

       \begin{SomeEnvironment}
           lots more stuff here as well
       \end{SomeEnvironment}
    \end{document}
\end{filecontents*}

% This file does not have a preamble so won't need a call to "\DisablePreamble"
\begin{filecontents*}{goo.tex}
    \MyToken={goobar}%   <----- Only this line should be executed. ALL other lines in foo.tex are to be ignored.
\end{filecontents*}

%% ------------------------------
%% Problem is in here somewhere!!  Shows up once we uncomment "\ExtractMyToken{foo}" below.
\makeatletter% <---- This was missing!!!!!
\newcommand{\DisablePreamble}{%
        \renewcommand{\documentclass}[2][]{}%  remove def'n of \documentclass
        %% http://tex.stackexchange.com/questions/165258/how-to-ignore-everything-in-the-document-environment
        \providecommand{\env@document@save@env}{}% To keep environ happy
        \providecommand{\env@document@process}{}%
        \RenewEnviron{document}{\endgroup\begingroup}% Ignore everything within the "document" environment.
        \renewcommand{\usepackage}[2][]{}% 
}%
\makeatother

\newtoks{\MyToken}
\newcommand{\FileWithPath}{}%
\newcommand{\ExtractMyTokenA}[1]{% Same as \ExtractMyTokenB, except invokes "\DisablePreamble" 
    % #1 = File Name with path
    \begingroup%
        \DisablePreamble%
        % -----------
        \let\OldInput\input%         Need to redefine \input as the file being read uses
        \renewcommand*{\input}[1]{}% \input before \begin{document}.
        % -----------
        \edef\FileWithPath{#1}%
        \OldInput{\FileWithPath}%
        \global\MyToken=\expandafter{\the\MyToken}
    \endgroup%
}%

\newcommand{\ExtractMyTokenB}[1]{% Same as \ExtractMyTokenA, except "\DisablePreamble" is commented.
    % #1 = File Name with path
    \begingroup%
        %\DisablePreamble% This works great for the case where there is no preamble.
        % -----------
        \let\OldInput\input%         Need to redefine \input as the file being read uses
        \renewcommand*{\input}[1]{}% \input before \begin{document}.
        % -----------
        \edef\FileWithPath{#1}%
        \OldInput{\FileWithPath}%
        \global\MyToken=\expandafter{\the\MyToken}
    \endgroup%
}%


\begin{document}
    \ExtractMyTokenB{goo}%  <----- This does not invoke \DisablePreamble, and works 
    MyToken=\the\MyToken\par
    % ------------
    \ExtractMyTokenA{foo}%   <----- This invokes \DisablePreamble, which fails 
    MyToken=\the\MyToken\par
\end{document}

相关内容