我有一份包含多组问题的文件,这些问题集中在不同的版本中。我希望能够使用单个参数选择生成哪个版本。该文件经常更新,这意味着我正在寻找一种模块化、简单且高效的方式来维护该文件。
到目前为止,我已经研究了 etoolbox(用于条件测试)、xparse(用于字符串比较)和注释包。我所取得的最好成绩是每个版本使用一个标志,并在我的序言中维护版本列表:
\excludecomment{v1}
\excludecomment{v2}
...
\excludecomment{v9}
\includecomment{v10}
\begin{document}
\begin{v1}
This is version 1.
\end{v1}
...
\end{document}
这种方法效果很好,但有点麻烦。我宁愿不必维护版本列表:
\generateversion{v10}
\begin{document}
\begin{version}{v1}
This is v1.
\end{version}
...
\end{document}
理想情况下,我正在寻找以下行为:
- 如果
generateversion
不存在且没有begin{version}
:照常进行 - 如果
generateversion
不存在且至少有一个begin{version}
:只取一个(理想情况下是最新的一个) - 如果
generateversion
存在并且没有begin{version}
或者不正确:发出错误 - 如果
generateversion
存在且正确begin{version}
:只取那一个有人知道该怎么做吗?
答案1
以下是您可以根据所指定要求使用的示例:
\documentclass{article}
\usepackage{environ}
% Conditions:
% 1) If \generateversion is absent and there is no \begin{version}: do as usual;
% - Met by default, as text will be set as usual.
% 2) If \generateversion is absent and there is at least one \begin{version}: take only one (ideally, the most recent one);
% - "The most recent one" will be the first one
% 3) If \generateversion is present and there is no \begin{version} or not the right one: issue an error;
% 4) If \generateversion is present and there is right \begin{version}: take only that one;
\newif\ifversionpresent
\newif\ifversionused
\makeatletter
\NewEnviron{version}[1]{%
\ifcsname @generateversion\endcsname
\ifnum\pdfstrcmp{#1}{\@generateversion}=0
\BODY% Do whatever with the body content (4)
\global\versionusedtrue
\fi
\else
\ifversionpresent\else
\BODY% Do whatever with the body content (2)
\global\versionusedtrue
\fi
\fi
\global\versionpresenttrue% version environment was used
}
\AtEndDocument{%
\ifcsname @generateversion\endcsname% \generateversion was used
\ifversionused\else% No or incorrect version (3)
\@latex@error{Incorrect version or no \string\begin\string{version\string}.}{}
\fi
\fi
}
\newcommand{\generateversion}[1]{\gdef\@generateversion{#1}}% Store version
\@onlypreamble\generateversion% You can only use \generatevesion in the preamble
\makeatother
\generateversion{v1}
\begin{document}
\begin{version}{v1}
Version \texttt{v1}.
\end{version}
\begin{version}{v2}
Version \texttt{v2}.
\end{version}
\begin{version}{v3}
Version \texttt{v3}.
\end{version}
\end{document}
\generateversion
输出前言中没有任何内容:
版本 v1。
\generateversion{v2}
序言中的输出:
版本 v2。
\generateversion{v4}
序言中的输出:
LaTeX 错误:版本不正确或没有
\begin{version}
。
如果不指定任何version
环境,LaTeX 会打印文档主体中找到的任何内容。这是默认行为;您的“照常行事”。
答案2
在下面的例子中,您确实必须生成 \ifvone 等等,但只需打开您想要的那个。
\documentclass{book}
\newif\ifvone
\newif\ifvtwo
\newif\ifvthree
\vtwotrue
\begin{document}
\ifvone
v1 true
\fi
\ifvtwo
v2 true
\fi
\ifvthree
v3 true
\fi
\end{document}
答案3
我遇到了和你一样的问题,我解决了,但是我使用了 Makefile。我认为这是最漂亮的解决方案,因为你不需要在编译之前修改文档。
例如,这是我用来编译“攻击性文档版本”的代码(在我的出版物中,我可以使用脏话,但在不冒犯版本中他们没有出现)。
Makefile 部分
在我的 makefile 中,我将以下几行放在文档顶部:
ifdef NOOFFENSIVE
TEXARGS += \\let\\isoffensive\\undefined
endif
ifdef OFFENSIVE
TEXARGS += \\def\\isoffensive{1}
SUFFIX :=${SUFFIX}-offensive
endif
在我的 makefile 中我定义了COMPIL
如下操作:
ifdef TEXARGS
COMPIL = ${TEX} -jobname=${PROCNAME} "${TEXARGS} \input{main.tex}"
else
COMPIL = ${TEX} -jobname=${PROCNAME} "\input{main.tex}"
endif
注意:预测没有定义选项的情况非常重要。
LaTeX 代码部分
在 LaTeX 项目的序言中(包声明之后),你必须输入:
\DeclareOption{offensive}{\def\isoffensive{1}}
\DeclareOption{nooffensive}{%
%\let\isoffensive\undefined
}
因此你可以定义如下命令:
\ifdefined\isoffensive
\newcommand{\offensive}[2]{#1}
\else
\newcommand{\offensive}[2]{#2}
\fi
因此你可以在你的项目中使用它,例如\offensive{Suck my *ss, b*ch!}{Sorry mister, but I couldn’t}
注意:第一个参数包含攻击形式。
命令行部分
在您的 LaTeX 项目中,要使用攻击性形式进行编译,您只需执行以下操作:
make OFFENSIVE=true
或者
make NOOFFENSIVE=false
对于 nooffensive 变体:
make OFFENSIVE=false
或者
make NOEFFENSIVE=true
默认情况下,如果你不指定任何参数,则将获得不冒犯版本。
您还可以将此选项与其他选项组合使用,例如可打印将可点击链接转换为脚注的参数。
答案4
当您要求模块化解决方案时,一种简单但更安全的方法(无需处理复杂的条件或字符串比较)是将每组问题保存在单独的文件中(表示A.tex
,, ...B.tex
每个C.tex
文件都有一行文本“ This is the version A
”等)
A.tex
然后,您可以在主文档中插入子文档\include{A}
,并用注释省略它,即, %\include{A}
或者从列表中排除“A”\includeonly{A,B,C...}
如果您不想\clearpage
在子文档之间插入,或者您需要在子文档之前/之后插入一些其他任意代码,而不是正常的\include{A}
(通常用于插入整个章节),您可以使用newclude
包的重新实现:
\include*[<code before>]{<filename>}[<code after>]
请注意星号和可选参数的特殊位置。如果没有这些选项, \include*{A} 的作用就如同\input{A}
,不同之处在于您仍然可以使用\includeonly{}
。
梅威瑟:
\documentclass{article}
\usepackage{newclude}
\includeonly{A,C} % just change this list
\begin{document}
\include*{A}
\include*{B}
\include*{C}
\end{document}
这将产生:
这是版本 A
这是版本 C
笔记:不清楚您是在搜索简单的考试设计还是其他内容。在第一种情况下,请查看CTAN 考试主题如果你是 Linux 用户,也可以尝试自动多项选择 (AMC)轻松选择和打乱问题顺序。这是一个带有 GUI 的程序,用于打印考试,然后对扫描的答案进行评分,但仍然是这里的主题,因为设计的任务只是使用.tex
必须使用 LaTeX 包的普通文件启动 LaTeX 编辑器automultiplechoce.sty
。