稍后在 tex 文件中引用先前定义的环境内容

稍后在 tex 文件中引用先前定义的环境内容

问题

稍后在 tex 文件中引用先前定义的环境内容的最佳方法是什么?具体来说,可以包含其他 latex 命令而不仅仅是文本的内容?

有关的:标记文本并在稍后引用(纯文本)

目标

为考试解决方案创建一个单独的页面。

执行

为了实现这一点,我创建了一个新环境sol,该环境包装了docclasssolution的原生环境exam。然后,该包装器为解决方案主体内容创建了一个标签,我稍后会使用它来引用。

sol环境:

\makeatletter
\NewEnviron{sol}{%
\def\@currentlabel{\BODY}\label{solt:\thequestion}%
\begin{solution}%
\protect\BODY
\end{solution}%
}
\makeatother

然后我会定义我的问题及其解决方案:

\begin{questions}

\begin{question}
Test Question

\begin{sol}
Test Solution
\includegraphics[width=3cm,height=3cm,keepaspectratio]{image.png}
\end{sol}
\end{question}

\end{questions}

最后使用自定义命令打印解决方案,该命令将查看每个问题并找到其标记的解决方案:

\newcommand\printsolutions{%
\begin{multicols*}{2}
\xintFor* ##1 in {\xintSeq{1}{\thequestion}} \do {%
\def\x{##1}
\noindent
\x) ~\ref{solt:\x}\\
\\
}
\end{multicols*}
}

总共有四个文件:

  • index.tex 包含配置和包含
  • questions.tex 包含问题
  • solutions.tex 包含解决方案
  • index-solutions.tex 用于将解决方案编译成 pdf

索引.tex

\documentclass[addpoints,12pt]{exam}
\usepackage{amsmath}
\usepackage{graphicx}
\usepackage{array}
\usepackage{blindtext}
\usepackage{xintexpr}
\usepackage{pgffor}
\usepackage{environ}
\usepackage{multicol}

\makeatletter
\NewEnviron{sol}{%
\def\@currentlabel{\BODY}\label{solt:\thequestion}%
\begin{solution}%
\protect\BODY
\end{solution}%
}
\makeatother

\newcommand\printsolutions{%
\begin{multicols*}{2}
\xintFor* ##1 in {\xintSeq{1}{\thequestion}} \do {%
\def\x{##1}
\noindent
\x) ~\ref{solt:\x}\\
\\
}
\end{multicols*}
}

\begin{document}

\include{questions}
\include{solutions}

\end{document}

问题.tex

\begin{questions}

\begin{question}
Test Question

\begin{sol}
Test Solution
\protect\includegraphics[width=3cm,height=3cm,keepaspectratio]{image.png}
\end{sol}
\end{question}
\begin{questions}

解决方案.tex

\section*{\centering Solutions}

\printsolutions

索引-解决方案.tex

\includeonly{solutions}
\input{index}

问题

这种方法在 90% 的情况下都有效,但当 \BODY 参数包含诸如 \includegraphics 命令之类的元素时,这种方法就会失败。如果我保护 \includegraphics 命令,它就会完美地工作。我猜是因为它不会立即扩展 includegraphics 命令。

由于我无法始终知道 \BODY 的内容,因此我无法手动浏览并在麻烦的命令(例如 \includegraphics)上设置 \protect。有没有更好的方法可以解决这个问题?

答案1

您之所以\protect提供帮助,是因为\label使用\protected@write将“受保护的扩展”写入\@currentlabel文件.aux。但是,正如您所想的那样,使用这种方法需要保护很多东西;因此,这种方法不太实用。

将解决方案存储在宏中可能是一种成功的方法,但它需要一个棘手的方面:在您的输入中,sol环境嵌入在中question,它本身嵌入在中questions,并且在“仅打印解决方案”用例中,您不想打印问题文本。所以,在这种情况下(\ifmyPrintEverything在我的例子中是当为假时),我定义questions环境,以便它将question环境定义为忽略所有内容,直到找到\begin{sol}。这必须使用递归来完成,因为据我所知,在定义宏时,不能在分隔参数后的标记中使用带有 catcode 1 或 2 的括号(换句话说:我不能简单地用作\begin{sol}宏参数分隔符,但使用\begin是可以的;只需要检查是否{sol}跟随,如果不跟随,则递归)。

以下代码适用于与示例中相同的简单结构:只有一个sol环境作为主体中的最后一个内容question,并且肯定没有sol环境,等等。如果您的环境没有以其环境结尾,subquestions那么这有点愚蠢,并且不会起作用。无论如何,我希望这能有所帮助。questionsol

常见.tex:

\documentclass[addpoints,12pt]{exam}
\usepackage{graphicx}
\usepackage{expl3}
\usepackage{environ}
\usepackage{multicol}
\usepackage{etoolbox}

\ExplSyntaxOn
% Borrow \int_step_inline:nnn from expl3
\cs_new_eq:NN \intstepinline \int_step_inline:nnn
\ExplSyntaxOff

\newif\ifprintSolutionsmode     % initially false
\newtoks\mytoks

\makeatletter
\NewEnviron{sol}{%
  \mytoks=\expandafter{\BODY}%
  \csxdef{my@sol@\number\value{question}}{\the\mytoks}%
  \unless\ifprintSolutionsmode
    \begin{solution}
      \BODY
    \end{solution}%
  \fi
}
\makeatother

\newcommand\printsolutions{%
  \begin{multicols*}{2}
    \intstepinline{1}{\number\value{question}}{%
      \noindent ##1) \csuse{my@sol@##1}\par\vspace{\baselineskip}
    }%
  \end{multicols*}
}

\begin{document}

\ifmyPrintEverything
  \printSolutionsmodefalse
\else
  \renewenvironment{questions}
    {\newenvironment{question}{\refstepcounter{question}\@my@skip@question}{}}
    {}
  \long\def\@my@skip@question#1\begin#2{%
    \ifstrequal{#2}{sol}{\begin{sol}}{\@my@skip@question}%
  }%
  \printSolutionsmodetrue
\fi

\input{questions}\newpage
\printsolutions

\end{document}

问题.tex:

\begin{questions}
  \begin{question}
    Test Question.

    \begin{sol}
      Test Solution.
      \includegraphics[width=3cm,keepaspectratio]{example-image}
    \end{sol}
  \end{question}
  \begin{question}
    This is another question.
    \begin{sol}
      Solution of the second question. \textbf{Non-expandable stuff}
      \def\zzz{is fine}\zzz.
    \end{sol}
  \end{question}
\end{questions}

启动解决方案.tex:

\newif\ifmyPrintEverything
\myPrintEverythingfalse

\input{common}

启动-all.tex:

\newif\ifmyPrintEverything
\myPrintEverythingtrue

\input{common}

编译start-all.tex结果:

在此处输入图片描述

编译start-solutions.tex结果:

在此处输入图片描述

相关内容