Makefile 部分

Makefile 部分

我有一份包含多组问题的文件,这些问题集中在不同的版本中。我希望能够使用单个参数选择生成哪个版本。该文件经常更新,这意味着我正在寻找一种模块化、简单且高效的方式来维护该文件。

到目前为止,我已经研究了 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

相关内容