假设您正在编写一本包含问题的书,并且您希望能够创建两个文档作为输出:一个包含书的文本和问题,另一个包含问题和解决方案。这似乎是一种相当常见的情况。您的文件的合理格式似乎是
\documentclass{book}
\newif\ifsolutions
\newif\iftext
\texttrue
%\solutionstrue
\newtheorem{theorem}{Theorem}
\newenvironment{problem}[1]{\item{\textit{#1}.}}{}
\begin{document}
\chapter{Theory}
\iftext
\begin{theorem}
If \(x\) and \(y\) then \(z\).
\end{theorem}
\fi
\section*{Problems}
\begin{enumerate}
\begin{problem}{Generalization}
Show that Theorem 1 can be generalized by dropping the requirement \(y\).
\ifsolutions
Solution:
First note that
\begin{equation}
a = b.
\end{equation}
The result follows from (1).
\fi
\end{problem}
\end{enumerate}
\end{document}
(对于真正的书,您可能会将章节放在单独的文件中并使用 \include 机制。)
如果要包含文本和问题,您可以设置\texttrue
;如果要包含问题和解决方案,您可以设置\solutionstrue
。
现在假设您想要包含超链接。文本和问题文件中的所有引用都可以是超链接。(我们假设文本中没有对解决方案中对象的引用。)但问题和解决方案文件中对文本中对象的引用不能是超链接 --- 它们必须是纯文本 --- 而该文件中对问题和解决方案中对象的引用应该是超链接。
一种方法是 (1) 使用两个宏来引用问题和解决方案中的引用,一个用于引用问题和解决方案中的引用,一个用于引用文本中的对象,以及 (2) 在aux
问题和解决方案文件中提供来自文本和问题文件的相关条目。因此,如下所示:
\documentclass{book}
\usepackage{hyperref}
\def\theoremautorefname{Theorem}
\newif\ifsolutions
\newif\iftext
%\texttrue
\solutionstrue
\iftext
\def\xautoref#1{\autoref{#1}}
\else
\def\xautoref#1{\autoref*{#1}}
\newlabel{theorem}{{1}{1}{Theory}{theorem.1}{}}
\fi
\newtheorem{theorem}{Theorem}
\newenvironment{problem}[1]{\item{\textit{#1}.}}{}
\begin{document}
\chapter{Theory}
\iftext
\begin{theorem}\label{theorem}
If \(x\) and \(y\) then \(z\).
\end{theorem}
\fi
\section*{Problems}
\begin{enumerate}
\begin{problem}{Generalization}
Show that \xautoref{theorem} can be generalized by dropping the requirement \(y\).
\ifsolutions
Solution:
First note that
\begin{equation}\label{equation}
a = b.
\end{equation}
The result follows from \autoref{equation}.
\fi
\end{problem}
\end{enumerate}
\end{document}
这种方法可行,但需要根据问题和解决方案中的链接是问题和解决方案内部的链接还是指向文本来对其进行编码,还需要手动包含\newlabel
来自文本和问题的辅助文件中的相关 s。更好的方法似乎是对所有超链接使用单个宏,并让计算机确定是使用纯文本还是超链接,如果是纯文本,则确定要放置什么纯文本,而无需手动从文本和问题文件中\newlabel
复制 s 。aux
这似乎要求系统在创建问题和解决方案文件时,首先aux
为文本和问题文件创建一个文件,然后检查每个超链接是否从该文件中获取内容并将其显示为纯文本,或者从问题和解决方案文件的辅助文件中获取内容并将其显示为超链接。在 LaTeX 中实现这一点似乎有点困难。可行吗?或者有更好的方法吗?
答案1
我的建议是,在文本和解决方案组件的规范中更加详细。为此,我定义了环境,textpart
并且solnpart
其下方应包含文档的文本和解决方案部分。此外,对文档中任何组件的引用textpart
都应使用\textref
。只有这些类型的引用才应得到特殊处理。
\documentclass{book}
\usepackage{amsmath,environ,etoolbox,hyperref}
\newif\ifsolutions
\newif\iftext
\newcommand{\textref}[1]{\iftext\ref{#1}\else\ref*{#1}\fi}
\textfalse
%\solutionstrue
\newtheorem{theorem}{Theorem}
\newenvironment{problem}[1]{\item \textit{#1}.}{}
\makeatletter
\newcommand{\textlabel}[1]{%
\listxadd{\labellist}{{#1}{\@currentlabel}}%
}
\newcommand{\setcurrentlabel}[2]{\def\@currentlabel{#2}}%
\newcommand{\setlabel}[2]{\label{#1}}%
\newsavebox{\gobblebox}
\NewEnviron{textpart}{%
\iftext
\BODY % Set the text part as-is
\else
\def\labellist{}% Clear the list of labels
\savebox{\gobblebox}{%
\begin{minipage}{\textwidth}
\let\label\textlabel% All \labels will be stored
\BODY % Store the text part in a box (and never set it)
\end{minipage}}
\renewcommand*{\do}[1]{% How each store \label will be processed
\setcurrentlabel##1%
\setlabel##1
}%
\expandafter\dolistloop\expandafter{\labellist}%
\fi
}
\makeatother
\NewEnviron{solnpart}{%
\ifsolutions
\BODY % Set the solution part as-is
\else
\begin{lrbox}{\gobblebox}
\begin{minipage}{\textwidth}
\BODY % Store the solution part in a box (and never set it)
\end{minipage}
\end{lrbox}
\fi
}
\begin{document}
\chapter{Theory}
\begin{textpart}
\begin{theorem}
If \(x\) and \(y\) then \(z\). \label{thm:theorem}
\end{theorem}
\end{textpart}
\section*{Problems}
\begin{enumerate}
\begin{problem}{Generalization}
Show that Theorem~\textref{thm:theorem} can be generalized by dropping the requirement \(y\).
\label{prb:problem}
\ifsolutions
Solution:
First note that, based on Theorem~\textref{thm:theorem} and Problem~\ref{prb:problem},
\begin{equation}
a = b. \label{eqn:equation}
\end{equation}
The result follows from~\eqref{eqn:equation}.
\fi
\end{problem}
\end{enumerate}
\end{document}
环境背后的想法textpart
是捕获所有使用并将和的当前值\label{<label>}
存储在列表中。然后,在结束时,处理项目列表并为每个项目发出单独的 ,并根据需要进行设置。这将产生正确的引用,但不是正确的名称或页码。但是,可以扩展定义以包含这一点。<label>
\@currentlabel
textpart
\label
\@currentlabel
此外,\textref
设置 a\ref
或 a \ref*
,取决于\texttrue
或\textfalse
。
代码可以简化为仅使用一个条件(\iftext
),因为您只需要两个文档选项:(1)文本和问题或(2)问题和解决方案。
这是一个存储与相关的所有组件的更新\label
,允许您使用\autoref
(例如):
\documentclass{book}
\usepackage{amsmath,environ,etoolbox,hyperref}
\newif\ifsolutions
\newif\iftext
\newcommand{\textref}[1]{\iftext\autoref{#1}\else\autoref*{#1}\fi}
\textfalse
%\solutionstrue
\newtheorem{theorem}{Theorem}
\newenvironment{problem}[1]{\item \textit{#1}.}{}
\makeatletter
\newcommand{\textlabel}[1]{%
\listxadd{\labellist}{{#1}{\@currentlabel}{\thepage}{\@currentlabelname}{\@currentHref}}%
}
\newcommand{\setcurrentlabels}[5]{%
\def\@currentlabel{#2}%
\def\thepage{#3}%
\def\@currentlabelname{#4}%
\def\@currentHref{#5}%
}%
\newcommand{\setlabel}[5]{\label{#1}}%
\newsavebox{\gobblebox}
\NewEnviron{textpart}{%
\iftext
\BODY % Set the text part as-is
\else
\def\labellist{}% Clear the list of labels
\savebox{\gobblebox}{%
\begin{minipage}{\textwidth}
\let\label\textlabel% All \labels will be stored
\BODY % Store the text part in a box (and never set it)
\end{minipage}}
\renewcommand*{\do}[1]{% How each store \label will be processed
\setcurrentlabels##1%
\setlabel##1
}%
\dolistloop{\labellist}%
\fi
}
\makeatother
\NewEnviron{solnpart}{%
\ifsolutions
\BODY % Set the solution part as-is
\else
\begin{lrbox}{\gobblebox}
\begin{minipage}{\textwidth}
\BODY % Store the solution part in a box (and never set it)
\end{minipage}
\end{lrbox}
\fi
}
\begin{document}
\chapter{Theory}
\begin{textpart}
\begin{theorem}
If \(x\) and \(y\) then \(z\). \label{thm:theorem}
\end{theorem}
\end{textpart}
\section*{Problems}
\begin{enumerate}
\begin{problem}{Generalization}
Show that \textref{thm:theorem} can be generalized by dropping the requirement \(y\).
\label{prb:problem}
\ifsolutions
Solution:
First note that, based on \textref{thm:theorem} and \autoref{prb:problem},
\begin{equation}
a = b. \label{eqn:equation}
\end{equation}
The result follows from~\eqref{eqn:equation}.
\fi
\end{problem}
\end{enumerate}
\end{document}