环境中的 \BODY 中的逐字内容

环境中的 \BODY 中的逐字内容

我想打印一份针对不同操作系统的 TeX 安装指南,但大多数文本对于所有操作系统都是相同的。因此我构建了以下内容

\documentclass{article}

\usepackage{environ}
\newcommand{\mlw}[3]{}
\NewEnviron{multichaps}{%
   \renewcommand{\mlw}[3]{##1}%
   \BODY
   \renewcommand{\mlw}[3]{##2}%
   \BODY
   \renewcommand{\mlw}[3]{##3}%
   \BODY
}

\begin{document}
\begin{multichaps}
\section{Installation on \mlw{Mac}{Windows}{Linux}}
Now it's time to test the system. Create a file
test.tex with the follwoing content.
\begin{verbatim}
\documentclass{article}

\begin{document}
Hallo World!
\end{document}
\end{verbatim}
Now open your \mlw{Terminal}{Command Promt}{Terminal}
and call \verb+pdflatex test+
\end{multichaps}
\end{document}

\mwl可以将文本设置为仅出现在一个操作系统的文本中,或者为不同的操作系统设置不同的文本。一切正常,但当我尝试verbatim在正文中使用时,它会崩溃。

是否可以做到这一点或者是否有其他方法可以做这样的事情?

答案1

环境environ像宏一样一次性读取其内容,因此不是“真实”环境,而是伪环境(看起来像环境,工作方式像宏)。这不允许像普通宏一样逐字内容。在启用逐字模式之前会读取内容,因此所有代码都已解析和分类。

为了解决这个问题,您需要使用正常环境,然后多次复制内容。通常可以通过将内容存储在保存箱中来完成此操作,但您的三种替代方案不允许这样做,因为装箱将修复内容。相反,您应该将内容写入外部文件并多次读取。这可以自动完成,而无需手动filecontents环境。包提供了一种简单的方法,listings如我在将环境主体逐字写入文件

\documentclass{article}

\makeatletter
\RequirePackage{listings}
\lst@RequireAspects{writefile}

\newcommand{\mlw}[3]{}
\newcommand{\mlwa}[3]{#1}
\newcommand{\mlwb}[3]{#2}
\newcommand{\mlwc}[3]{#3}

\lstnewenvironment{multichaps}{%
  % Write file to given filename
  \lst@BeginWriteFile{\jobname.mul}%
}
{%
  \lst@EndWriteFile% closes output file
  \let\mlw\mlwa
  \input{\jobname.mul}%
  \let\mlw\mlwb
  \input{\jobname.mul}%
  \let\mlw\mlwc
  \input{\jobname.mul}%
}
\makeatother

\begin{document}

\begin{multichaps}
\section{Installation on \mlw{Mac}{Windows}{Linux}}
Now it's time to test the system. Create a file
test.tex with the follwoing content.
\begin{verbatim}
\documentclass{article}

\begin{document}
Hallo World!
\end{document}
\end{verbatim}
Now open your \mlw{Terminal}{(Eingabeaufforderung)}{Terminal}
and call \verb+pdflatex test+
\end{multichaps}

\end{document}

或者,您可以将内容逐字存储在宏中,然后使用 e-TeX 的 重新评估它\scantokens,这与将其写入外部文件并重新读取基本相同,但效率更高。这里的一个问题似乎是行尾 (EOF) 字符的处理。例如,可以使用我的newverbs包将内容存储在宏中。但是,它尚未提供环境变体,因此您需要使用宏版本:

\documentclass{article}

\usepackage{newverbs}

\newcommand{\mlw}[3]{}
\newcommand{\mlwa}[3]{#1}
\newcommand{\mlwb}[3]{#2}
\newcommand{\mlwc}[3]{#3}

\makeatletter
\newcommand{\multichaps}{%
    \begingroup
    \expandafter\Collectverb\expandafter\@multichaps\expandafter
}

% The EOL character must be active to work with 'verbatim'.
% By default it should produce a space.
% This will break implicit paragraphs!
\begingroup
\catcode13=\active%
\gdef\activenl{%
    \catcode13=\active%
    \let^^M\space%
}%
\endgroup%

\newcommand{\@multichaps}[1]{%
  \activenl
  \let\mlw\mlwa
  \scantokens{#1}%
  \let\mlw\mlwb
  \scantokens{#1}%
  \let\mlw\mlwc
  \scantokens{#1}%
  \endgroup
}
\makeatother

\begin{document}

\multichaps=
\section{Installation on \mlw{Mac}{Windows}{Linux}}
Now it's time to test the system. Create a file
test.tex with the follwoing content.
\begin{verbatim}
\documentclass{article}

\begin{document}
Hallo World!
\end{document}
\end{verbatim}
Now open your \mlw{Terminal}{(Eingabeaufforderung)}{Terminal}
and call \verb+pdflatex test+
=

\end{document}

答案2

在 ConTeXt 中,存储和操作主体环境(不将其存储为宏)的标准方法是使用buffers。例如,这是在 ConTeXt 中编写相同宏的方式,并且它可以按预期工作。

\let\mlw\gobblethreearguments

\def\startmultichapters
    {\grabbufferdata[multichapters][startmultichapters][stopmultichapters]}

\def\stopmultichapters
    {\let\mlw\firstofthreearguments
     \getbuffer[multichapters]%
     \let\mlw\secondofthreearguments
     \getbuffer[multichapters]%
     \let\mlw\thirdofthreearguments
     \getbuffer[multichapters]%
     \let\mlw\gobblethreearguments}

\starttext
\startmultichapters
  \startsection[title={\mlw{foo}{bar}{baz}}]
    This is some text in section \mlw{foo}{bar}{baz}
    \starttyping
      Crash
    \stoptyping
  \stopsection
\stopmultichapters
\stoptext

笔记:如果您使用的是旧版本的 ConTeXt(2012 年 2 月之前),则需要将其替换\grabbufferdata\dostartbuffer

据我所知,LaTeX 没有与 ConTeXt 缓冲区等效的缓冲区。最接近的方法是使用环境filecontents将内容写入外部文件(在 MkII 中,ConTeXt 缓冲区也将内容写入外部文件;但在 MkIV 中,内容保存在内存中)。请参阅 Taco Hoekwater 对LaTeX 相当于 ConTeXt 缓冲区

答案3

有时候,人们会只见树木不见森林……我没有想过将内容放入外部文件并将其包含三次……

\begin{filecontents}{multichapsbody.tex}
\section{Installation on \mlw{Mac}{Windows}{Linux}}
Now it's time to test the system. Create a file
test.tex with the follwoing content.
\begin{verbatim}
\documentclass{article}

\begin{document}
Hallo World!
\end{document}
\end{verbatim}
Now open your \mlw{Terminal}{(Eingabeaufforderung)}{Terminal}
and call \verb+pdflatex test+
\end{filecontents}

\documentclass{article}

\newcommand{\mlw}[3]{}

\begin{document}
\renewcommand{\mlw}[3]{#1}
\input{multichapsbody}

\renewcommand{\mlw}[3]{#2}
\input{multichapsbody}

\renewcommand{\mlw}[3]{#3}
\input{multichapsbody}
\end{document}

答案4

您的另一个答案,但无需编写外部文件:)

\documentclass{article}
\usepackage{scontents}
\begin{scontents}[store-env=multichapsbody]
\section{Installation on \mlw{Mac}{Windows}{Linux}}
Now it's time to test the system. Create a file
test.tex with the follwoing content.
\begin{verbatim}
\documentclass{article}

\begin{document}
Hallo World!
\end{document}
\end{verbatim}
Now open your \mlw{Terminal}{(Eingabeaufforderung)}{Terminal}
and call \verb+pdflatex test+
\end{scontents}
\setlength{\parindent}{0pt}
\pagestyle{empty}
\newcommand{\mlw}[3]{}
\begin{document}

\renewcommand{\mlw}[3]{#1}
\getstored[1]{multichapsbody}

\renewcommand{\mlw}[3]{#2}
\getstored[1]{multichapsbody}

\renewcommand{\mlw}[3]{#3}
\getstored[1]{multichapsbody}
\end{document}

输出 问候语

相关内容