更新。

更新。

当我为学生准备练习列表时,我也会在其中加入自己的解决方案。我根据宏准备了这些文档,mdframed借助这些comment宏,我轻松获得了两个 pdf,一个包含练习,另一个包含练习和解决方案。

我鼓励我的学生尝试用 编写解决方案,LaTeX因此我给他们一个.pdf包含练习的文件和一个.tex不包含答案的源文件。这样,他们只需要担心编写解决方案,因为格式已经提供。问题是我需要两个源文件,一个包含问题+解决方案,另一个仅包含问题。

我希望只有一个.tex包含问题和解决方案的文件,并且能够从中提取另一个.tex不包含解决方案的文件。作为一个可能的框架,假设主.tex文件如下:

% This is main.tex file
\documentclass{article}
\begin{document}
\begin{exercise} 
This is the first exercise
\begin{solution}
This is my solution
\end{solution}
\end{exercise}
\end{document}

我想从中轻松获得一个具有空解决方案的类似解决方案:

% This is student.tex file
\documentclass{article}
\begin{document}
\begin{exercise} 
This is the first exercise
\begin{solution}
\end{solution}
\end{exercise}
\end{document}

我想我正在寻找类似.dtx文件的东西,但我从未使用过它,也许有更好的解决方案。我正在使用 Windows,因此grep命令不起作用。

答案1

更新。

增加了支持在副本中保留空环境,仅删除其内容,或者也删除该\begin...\end对(默认)。


我编写了一个 LuaLaTeX 解决方案,并尝试使其足够灵活。这些是组成该解决方案的文件:

remove-env.lua

-- remove-env.lua
omittedEnvironments = {}
omitFileSuffix = "-without"
leaveEmptyEnvs = false

function shouldOmit(line)
  for i,v in ipairs(omittedEnvironments) do
    if (string.find(line, "\\begin{"..v.."}")~=nil) then
       return true
    end
  end
  return false
end

function shouldResume(line)
  for i,v in ipairs(omittedEnvironments) do
    if (string.find(line, "\\end{"..v.."}")~=nil) then
       return true
    end
  end
  return false
end

function dumpfile()
    myout = io.open(tex.jobname..omitFileSuffix..".tex", "w")
    myin = io.open(tex.jobname..".tex", "r")
    omitting = false
    for line in myin:lines() do
      if (not omitting and shouldOmit(line)) then
          if (leaveEmptyEnvs) then myout:write(line.."\n") end
          omitting = true
      end
      if (not omitting) then
         myout:write(line.."\n")
      end
      if (omitting and shouldResume(line)) then
          if (leaveEmptyEnvs) then myout:write(line.."\n") end
          omitting = false
      end
    end
    myout:close()
    myin:close()
end

remove-env.tex

\directlua{dofile("remove-env.lua")}
\def\omitEnvironment#1{\directlua{table.insert(omittedEnvironments, "#1")}}
\def\omitFileSuffix#1{\directlua{omitFileSuffix="#1"}}
\def\leaveEmptyEnvs{\directlua{leaveEmptyEnvs=true}}
\def\removeEmptyEnvs{\directlua{leaveEmptyEnvs=false}}
\AtEndDocument{\directlua{dumpfile()}}

MWE.tex

\input remove-env
\documentclass{article}
\usepackage{fontspec}
\usepackage{lipsum}
\newenvironment{solution}{}{}
\omitEnvironment{solution}
\omitFileSuffix{-sans-sol}

\begin{document}\parindent0pt\parskip1em
  1. \lipsum[1]\hrulefill\par
  \begin{solution}
  2. \lipsum[2]\hrulefill\par
  \end{solution}
  3. \lipsum[3]\hrulefill\par
\end{document}

这个 MWE 定义了一个无操作solution环境,它仅充当标记,但当然你可以以一种在 pdf 中产生一些效果的方式定义它。宏\omitEnvironment指定你想要省略的环境。你可以多次使用此宏来指定多个环境,所有这些环境都将被省略。宏\omitFileSuffix指定将附加到输出文件名的后缀。

跑步:

$ lualatex MWE.tex

您将获得两个文件(当然还有所有常见的辅助文件):

  • MWE.pdf将像平常一样生成,并且所有内容(包括省略的环境)都将存在。
  • MWE-sans-sol.texMWE.tex是一份所有solution环境均已被删除的副本。
$ diff MWE.tex MWE-sans-sol.tex
11,13d10
<   \begin{solution}
<   2. \lipsum[2]\hrulefill\par
<   \end{solution}

如果您只想删除解决方案的内容但保留空环境,则只需\leaveEmptyEnvs在某个点指定MWE.tex。在这种情况下,diff 将显示:

$ diff MWE.tex MWE-sans-sol.tex
12d11
<   2. \lipsum[2]\hrulefill\par

附言:感谢 Scott H.建议我不要使用 luatex 回调,这是我的第一个(也是太复杂的)方法

答案2

仅适用于 TeX 的解决方案;它假定您没有任何其他环境,其名称以soluti之外的字符串开头solution

准备以下extract.tex文件:

\newread\texfileread
\newwrite\texfilewrite
\openin\texfileread=ignasimain.tex % put here the main file name
\immediate\openout\texfilewrite=ignasistudents.tex % put here the secondary file name

\edef\BEGINSOLUTI{\string\begin\string{soluti}
\edef\ENDSOLUTION{\string\end\string{solution}
\newif\ifwritesolution
\writesolutiontrue

\long\def\ignasidecide#1#2#3#4#5#6#7#8#9\relax{%
  \def\temp{#1#2#3#4#5#6#7#8}%
  \ignasidecideaux#9}
\long\def\ignasidecideaux#1#2#3#4#5#6\relax{%
  \ifnum\pdfstrcmp{\temp#1#2#3#4#5}{\BEGINSOLUTI}=0
    \immediate\write\texfilewrite{\ignasiline^^J}
    \writesolutionfalse
  \else
    \ifnum\pdfstrcmp{\temp#1#2#3#4#5}{\ENDSOLUTION}=0
      \writesolutiontrue
    \fi
  \fi
  \ifwritesolution
    \immediate\write\texfilewrite{\ignasiline}
  \fi
}

\endlinechar=-1 \newlinechar=`\^^J
\loop\unless\ifeof\texfileread%
\readline\texfileread to \ignasiline%
\expandafter\ignasidecide\ignasiline%
  \relax\relax\relax\relax%
  \relax\relax\relax\relax%
  \relax\relax\relax\relax%
  \relax\relax%
\repeat%
\csname bye\endcsname%
\csname @@end\endcsname

根据需要更改文件名。将此文件与主文件放在一起,然后使用pdftex或进行编译pdflatex(它们是相同的)。

使用示例文件,生成的文件将是

% This is main.tex file
\documentclass{article}
\begin{document}
\begin{exercise}
This is the first exercise
\begin{solution}

\end{solution}
\end{exercise}
\end{document}

基本上,我们逐行读取主​​文件(忽略类别代码)\readline;如果行以

\begin{soluti

然后我们写出该行,后面跟着一个空行,并将条件设置为 false;如果该行以

\end{solution

然后再次将条件设置为真。如果条件为真,则写出当前行。

答案3

我也遇到了同样的问题。我最终使用了docstrip

我设置的系统产生:

  • (i)将 tex 和 pdf 文件分别提供给我(附有解决方案)和学生(不带解决方案:),

  • (二)针对学生分组的练习的几个版本,以及

  • (iii) 排版仅选定的主题,允许我将所有练习保存在同一个文件中。

以下是包含练习和解决方案的主文件的概要:

% This is exercises.tex
\documentclass{article}
\newenvironment{exercise}{}{}
\newenvironment{solution}{}{}

\title{Subject\\\normalsize homework topic:
%<topic1>topic 1
%<topic2>topic 2
}
\author{}

\begin{document}
\maketitle

%<*topic1>
\begin{exercise}
  Exercise text (topic 1)
%<A>  Version for group A,
%<B>  Version for group B,
%<C>  Version for group C,
%<D>  Version for group D.
  More exercise text.
\end{exercise}
%<*!student>
\begin{solution}
  Solution, visible only in my copy:
%<A> for group A,
%<B> for group B,
%<C> for group C,
%<D> for group D.
\end{solution}
%</!student>

%<*student>
% Template for student's answer.
\begin{solution}

\end{solution}
%</student>

%</topic1>



%<*topic2>
\begin{exercise}
  Exercise text (topic 1)
%<A>  Version for group A,
%<B>  Version for group B,
%<C>  Version for group C,
%<D>  Version for group D.
  More exercise text.
\end{exercise}
%<*!student>
\begin{solution}
  Solution, visible only in my copy:
%<A> for group A,
%<B> for group B,
%<C> for group C,
%<D> for group D.
\end{solution}
%</!student>

%<*student>
% Template for student's answer.
\begin{solution}

\end{solution}
%</student>

%</topic2>

\end{document}

这是.ins文件topic1

% This is exercises.ins
\input docstrip
\nopreamble\nopostamble
\askforoverwritefalse
\generate{%
  \file{exercises-topic1-A.tex}{\from{exercises.tex}{student,topic1,A}}%
  \file{exercises-topic1-B.tex}{\from{exercises.tex}{student,topic1,B}}%
  \file{exercises-topic1-C.tex}{\from{exercises.tex}{student,topic1,C}}%
  \file{exercises-topic1-D.tex}{\from{exercises.tex}{student,topic1,D}}%
  \file{exercises-topic1-ME.tex}{\from{exercises.tex}{topic1,A,B,C,D}}%
  %\file{exercises-topic2-A.tex}{\from{exercises.tex}{student,topic2,A}}%
  %\file{exercises-topic2-B.tex}{\from{exercises.tex}{student,topic2,B}}%
  %\file{exercises-topic2-C.tex}{\from{exercises.tex}{student,topic2,C}}%
  %\file{exercises-topic2-D.tex}{\from{exercises.tex}{student,topic2,D}}%
  %\file{exercises-topic2-ME.tex}{\from{exercises.tex}{topic2,A,B,C,D}}%
}
\endbatchfile

最后,一个写得很糟糕的 makefile --- 其实只不过是一个伪装的 bash 脚本。(我猜,理想情况下,运行make应该会自动生成.ins文件...啊,总有一天...)

all:
    pdftex exercises.ins
    bash -c 'for I in {A,B,C,D,ME}; do pdflatex exercises-topic1-$$I ; done'
    #bash -c 'for I in {A,B,C,D,ME}; do pdflatex exercises-topic2-$$I ; done'

答案4

最简单的选择可能是提炼包,mbork 在评论中提到过。但是,这种方法不允许你将解决方案环境嵌套在练习环境中。

\documentclass{article}
\usepackage[
  active,
  header=false,
  copydocumentclass=true,
  generate=\jobname-no-solutions,
  extract-env={exercise}
  ]{extract} % http://ctan.org/pkg/extract
\begin{extract*}
% Items executed in both the main and extracted document
% (extract manual, section 5.1)
\newenvironment{exercise}{}{}
\newenvironment{solution}{}{}
\end{extract*}
\begin{document}
\begin{exercise} 
This is the first exercise
\end{exercise}
\begin{solution}
This is my solution
\end{solution}
\end{document}

提取文件后的代码如下:

\documentclass{article}
% Items executed in both the main and extracted document
% (extract manual, section 5.1)
\newenvironment{exercise}{}{}
\newenvironment{solution}{}{}

\begin{document}

\begin{exercise}
This is the first exercise
\end{exercise}

\end{document}

相关内容