我的问题出现在此egreg 的回答。
我有一个练习答案列表,但我不想立即显示答案,而是等到我用命令拉取并获取到那里的所有答案。
举例来说:
\hidesolutions
\begin{exercise} this is an exercise.1 \end{exercise}
\begin{solution} this is a solution for the above exercise.1 \end{solution}
\begin{exercise} this is an exercise.2 \end{exercise}
\begin{solution} this is a solution for the above exercise.2 \end{solution}
\stophidesolutions
\begin{exercise} this is an exercise.3 \end{exercise}
\begin{solution} this is a solution for the above exercise.3 \end{solution}
\hidesolutions
\begin{exercise} this is an exercise.4 \end{exercise}
\begin{solution} this is a solution for the above exercise.4 \end{solution}
\begin{exercise} this is an exercise.5 \end{exercise}
\begin{solution} this is a solution for the above exercise.5 \end{solution}
\stophidesolutions
\section{solutions}
\showsolutions
\showsolutions
结果应该是:
- 显示练习 1 和 2
- 显示练习 3 和他的答案
- 显示练习 4 和 5
- 显示新部分
solutions
- 显示答案 1 和 2
- 显示答案 4 和 5
答案1
有以下可能性:
\documentclass{book}
\usepackage{amsthm}
\usepackage{xparse}
\usepackage{environ}
\theoremstyle{definition} % body text is upright
\newtheorem{exercise}{Exercise}
\ExplSyntaxOn
\newtheorem*{innersolution}{Solution ~ of ~ \dvvv_exercise_ref:}
\NewEnviron{solution}
{
\seq_gput_right:Nx \g_dvvv_solution_group_seq { {\theexercise}{\exp_not:V \BODY} }
}
\NewDocumentEnvironment{solution*}{}
{
\cs_set:Npx \dvvv_exercise_ref: { \theexercise }
\innersolution
}
{
\endinnersolution
}
\NewDocumentCommand{\printsolutions}{}
{
\seq_map_inline:Nn \g_dvvv_solution_group_seq
{
\dvvv_print_solutions:nn ##1
}
\seq_gclear:N \g_dvvv_solution_group_seq
}
\seq_new:N \g_dvvv_solution_group_seq
\cs_new_protected:Npn \dvvv_print_solutions:nn #1 #2
{
\cs_set:Npn \dvvv_exercise_ref: { #1 }
\begin{innersolution} #2 \end{innersolution}
}
\ExplSyntaxOff
\begin{document}
\chapter{Title}
\section{Exercises}
\begin{exercise}
This is an exercise.
\end{exercise}
\begin{solution}
A solution.
\end{solution}
\begin{exercise}
This is an exercise.
\end{exercise}
\begin{solution}
A solution.
\end{solution}
\begin{exercise}
This is an exercise.
\end{exercise}
Some optional text in between.
\begin{solution*}
This is a solution.
\end{solution*}
The solution has been printed immediately, because
\texttt{solution*} has been used.
\begin{exercise}
This is another exercise.
\end{exercise}
\begin{solution}
A solution.
\end{solution}
\begin{exercise}
This is yet another exercise.
\end{exercise}
\begin{solution}
Too much.
\end{solution}
\section{Solutions}
\printsolutions
\end{document}
解决方案存储在 FIFO 列表中;使用solution*
可当场打印解决方案。
以下是相同的,但支持超链接:
\documentclass{book}
\usepackage{amsthm}
\usepackage{xparse}
\usepackage{environ}
\usepackage[colorlinks]{hyperref}
\theoremstyle{definition} % body text is upright
\newtheorem{innerexercise}{Exercise}
\ExplSyntaxOn
\NewDocumentEnvironment{exercise}{}
{
\innerexercise\label{dvvv_ \theinnerexercise _label}
}
{
\endinnerexercise
}
\newtheorem*{innersolution}{\dvvv_exercise_ref:}
\NewEnviron{solution}
{
\seq_gput_right:Nx \g_dvvv_solution_group_seq
{
{\theinnerexercise}{\exp_not:V \BODY}
}
}
\NewDocumentEnvironment{solution*}{}
{
\cs_set:Npx \dvvv_exercise_ref:
{
\exp_not:N \hyperref
[
dvvv_ \theinnerexercise _label
]
{
Solution~of~\exp_not:N\ref*{dvvv_ \theinnerexercise _label}
}
}
\innersolution
}
{
\endinnersolution
}
\NewDocumentCommand{\printsolutions}{}
{
\seq_map_inline:Nn \g_dvvv_solution_group_seq
{
\dvvv_print_solutions:nn ##1
}
\seq_gclear:N \g_dvvv_solution_group_seq
}
\seq_new:N \g_dvvv_solution_group_seq
\cs_new_protected:Npn \dvvv_print_solutions:nn #1 #2
{
\cs_set:Npn \dvvv_exercise_ref:
{
\hyperref[dvvv_#1_label]{Solution~of~\ref*{dvvv_#1_label}}
}
\begin{innersolution} #2 \end{innersolution}
}
\ExplSyntaxOff
\begin{document}
\chapter{Title}
\section{Exercises}
\begin{exercise}
This is an exercise.
\end{exercise}
\begin{solution}
A solution.
\end{solution}
\begin{exercise}
This is an exercise.
\end{exercise}
\begin{solution}
A solution.
\end{solution}
\begin{exercise}
This is an exercise.
\end{exercise}
Some optional text in between.
\begin{solution*}
This is a solution.
\end{solution*}
The solution has been printed immediately, because
\texttt{solution*} has been used.
\begin{exercise}
This is another exercise.
\end{exercise}
\begin{solution}
A solution.
\end{solution}
\begin{exercise}
This is yet another exercise.
\end{exercise}
\begin{solution}
Too much.
\end{solution}
\section{Solutions}
\printsolutions
\end{document}
让我们一步一步地看一下第一个解决方案。第二个解决方案只是为每个exercise
环境自动添加一个标签设置,用于超链接,所以它不会复杂太多。
步骤1
定义一个exercise
环境;这是标准的
第2步
将环境定义innersolution
为无编号定理;标签文本取决于\dvvv_exercise_ref:
打印时设置的值
步骤3
定义一个solution
环境,借助\NewEnviron
,使 LaTeX 将环境的内容存储在宏 中\BODY
。宏的值与当前练习编号一起存储在一个序列中。
步骤4
环境solution*
只是将的值设置\dvvv_exercise_ref:
为当前练习编号并调用innersolution
步骤5
定义\printsolutions
命令,该命令只是映射序列,即传递给\dvvv_print_solutions:nn
其每个项目。最后它清除序列。
第 6 步
该\dvvv_print_solutions:nn
函数利用了解决方案以 格式存储的事实{<number>}{<contents>}
,因此它使用第一个参数来设置 的值\dvvv_exercise_ref:
,并将第二个参数提供给innersolution
环境。
反向链接(从练习到解决方案)
诀窍是在解决方案中添加另一个标签,并在练习中添加超链接。
\documentclass{book}
\usepackage{amsthm}
\usepackage{xparse}
\usepackage{environ}
\usepackage[colorlinks]{hyperref}
\newtheoremstyle{exercise}% name
{\topsep}% Space above
{\topsep}% Space below
{\normalfont}% Body font
{}% Indent amount (empty = no indent, \parindent = para indent)
{\bfseries}% Thm head font
{.}% Punctuation after thm head
{ }% Space after thm head
{\hyperref[dvvv_#2_reverse_label]{\thmname{#1}\thmnumber{ #2}}\thmnote{ (#3)}}% Thm head spec
\theoremstyle{exercise} % body text is upright
\newtheorem{innerexercise}{Exercise}
\theoremstyle{definition}
\ExplSyntaxOn
\NewDocumentEnvironment{exercise}{}
{
\innerexercise\label{dvvv_ \theinnerexercise _label}
}
{
\endinnerexercise
}
\newtheorem*{innersolution}{\dvvv_exercise_ref:}
\NewEnviron{solution}
{
\seq_gput_right:Nx \g_dvvv_solution_group_seq
{
{\theinnerexercise}{\exp_not:V \BODY}
}
}
\NewDocumentEnvironment{solution*}{}
{
\phantomsection\label{dvvv_ \theinnerexercise _reverse_label}
\cs_set:Npx \dvvv_exercise_ref:
{
\exp_not:N \hyperref
[
dvvv_ \theinnerexercise _label
]
{
Solution~of~\exp_not:N\ref*{dvvv_ \theinnerexercise _label}
}
}
\innersolution
}
{
\endinnersolution
}
\NewDocumentCommand{\printsolutions}{}
{
\seq_map_inline:Nn \g_dvvv_solution_group_seq
{
\dvvv_print_solutions:nn ##1
}
\seq_gclear:N \g_dvvv_solution_group_seq
}
\seq_new:N \g_dvvv_solution_group_seq
\cs_new_protected:Npn \dvvv_print_solutions:nn #1 #2
{
\cs_set:Npn \dvvv_exercise_ref:
{
\phantomsection\label{dvvv_#1_reverse_label}
\hyperref[dvvv_#1_label]{Solution~of~\ref*{dvvv_#1_label}}
}
\begin{innersolution} #2 \end{innersolution}
}
\ExplSyntaxOff
\begin{document}
\chapter{Title}
\section{Exercises}
\begin{exercise}
This is an exercise.
\end{exercise}
\begin{solution}
A solution.
\end{solution}
\begin{exercise}
This is an exercise.
\end{exercise}
\begin{solution}
A solution.
\end{solution}
\begin{exercise}
This is an exercise.
\end{exercise}
Some optional text in between.
\begin{solution*}
This is a solution.
\end{solution*}
The solution has been printed immediately, because
\texttt{solution*} has been used.
\begin{exercise}
This is another exercise.
\end{exercise}
\begin{solution}
A solution.
\end{solution}
\begin{exercise}
This is yet another exercise.
\end{exercise}
\begin{solution}
Too much.
\end{solution}
\clearpage
\section{Solutions}
\printsolutions
\end{document}
2019 年 3 月更新
从xparse
2019-03-05 或更高版本发布后,不再需要environ
。将代码替换solution
为
\NewDocumentEnvironment{solution}{+b}
{
\seq_gput_right:Nx \g_dvvv_solution_group_seq
{
{\theinnerexercise}{ \exp_not:n { #1 } }
}
}
{}
答案2
另一个解决方案是使用tcolorbox
。此包提供命令\tcbstartrecording[file]
,\tcbstoprecording
和 ,\tcbinputrecording[file]
可用作 OP\hidesolutions
和\stophidesolutions
。
Anytcolorbox
分为上下两部分。我们可以将上半部分用作练习,下半部分用作解决方案。Optionssavelowerto
会创建一个辅助文件,用于保存下半部分。可以使用 option 保存此文件以供日后使用record
。并且可以使用 将这些记录的片段包含到我们的文档中\tcbinputrecording
。
下一个代码显示了基于tcolorbox
文档中“7.3 示例:练习”和“13.9 创建 LaTeX 练习”中的代码的示例。
我还在tcblisting
问题和解决方案中添加了方框,因为它是作为对 NewEnviron、\BODY 和 lstlisting在我发布之前它就被关闭了。我认为对于这个问题来说也是有效的。
代码包含一些注释,我希望这些注释能够帮助理解它的工作原理
\documentclass{article}
\usepackage{lipsum}
\usepackage[most]{tcolorbox}
\usepackage{hyperref}
\NewTColorBox[auto counter,number within=section]{exercise}{+O{}}{%
enhanced, colframe=green!20!black, colback=yellow!10!white,
coltitle=green!40!black, fonttitle=\bfseries,
title={Exercise~\thetcbcounter:},
label={exercise@\thetcbcounter},
attach title to upper=\quad,
after upper={\par\hfill\textcolor{green!40!black}%
{\itshape Solution on page~\pageref{solution@\thetcbcounter}}},
lowerbox=ignored,
savelowerto=solutions/exercise-\thetcbcounter.tex,
record={\string\solution{\thetcbcounter}%
{solutions/exercise-\thetcbcounter.tex}},
#1}
\NewTotalTColorBox{\solution}{mm}{%
enhanced, colframe=red!20!black, colback=yellow!10!white,
coltitle=red!40!black, fonttitle=\bfseries,
title={Solution of Exercise~\ref{exercise@#1} on page~\pageref{exercise@#1}:},
phantomlabel={solution@#1},
attach title to upper=\par,
}{\input{#2}}
\tcbset{no solution/.style={no recording,after upper=}}
\newtcblisting{mylisting}{listing only}
\begin{document}
\section{Some problems}
% We start to record all `tcblower` parts in file `file1` for later provessing
\tcbstartrecording[file1]
%Every exercise box contains an upper part which is processed and
%printed and a lower (solution) which printing is delayed.
%
\begin{exercise}
Type some nice code
\begin{mylisting}
This is my
first listing
\end{mylisting}
\tcblower %<--------- Here upper part finishes and lower starts
The solution could be:
\begin{mylisting}
This is the solution
for the first listing problem
\end{mylisting}
\end{exercise}
\tcbstoprecording %<---- recording solutions in `file1` is finished.
% Recording mechanism has been stopped. Solutions are printed after
% upper part.
\begin{exercise}[lowerbox=visible] %<--- lowerbox is `invisible` in `exercise` boxes
Type some nice code
\tcblower
The solution could be:
\begin{mylisting}
My code 2
\end{mylisting}
\end{exercise}
% another file will continue recording solutions
\tcbstartrecording[file2]
\begin{exercise}
Type some nice code
\tcblower
The solution could be:
\begin{mylisting}
My code 3
\end{mylisting}
\end{exercise}
\tcbstoprecording
\section{Some solutions to previous problems}
%previous recorded files with solutions are processed and printed
\tcbinputrecords[file1]
\tcbinputrecords[file2]
\end{document}
之前的代码只是一个起点。一些细节,比如未记录解决方案的引用或样式,必须解决。无论如何,结果如下所示: