How to build two different .tex files from same .tex file

When I prepare an exercise list for my students I use to also include there my own solutions. I prepare these documents with some macros based on mdframed and with comment help I easily obtain two pdfs, one with exercises and another one with exercises and solutions.

I encourage my students to try to write their solutions with LaTeX so I give them the .pdf file with exercises and a source .tex file without answers. This way, they only have to worry about writing their solutions because the format is already provided. The problem is that I need to have two source files one with problems+solutions and another one only with problems.

What I would like would be to have only one .tex file with problems and solutions and, from it be able to extract another .tex file without solutions. As a possible frame work suppose a main .tex file like:

% 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}


from which I want to easily obtain a similar one with empty solutions:

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


I suppose I'm looking for something like a .dtx file but I've never used it and may be there are better solutions. I'm working on windows so grep commands won't work.

• I would write a short parser, which just cut out the text between \begin{solution} and \end{solution}. But I am not sure whether an analog is possible through LaTeX itself, too. – Dominikus K. Mar 8 '13 at 15:32
• Have you considered the exam document class? It won't give you two tex sources, but as @DominikusK. says, you can easily write a parser. – Sean Allred Mar 8 '13 at 15:51
• @JLDiaz: No. I do need two .tex files because I want to give one to the students. I know how to get different pdf from same file. – Ignasi Mar 8 '13 at 17:30
• @SeanAllred I know exam, exsheets, and some other classes for exercises. With them i can produce different pdfs but i want different source (.tex) files. – Ignasi Mar 8 '13 at 17:32
• Did you check the extract package? – mbork Mar 8 '13 at 22:19

Update.

Added support to leave the empty environment in the copy, removing only its contents, or to remove also the \begin...\end pair (by default).

I programmed a LuaLaTeX solution and tried to make it flexible enough. These are the files which compose the solution:

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}


This MWE defines a no-op solution environment which acts simply as markup, but of course you can define it in a way that produces some effect in the pdf. Macro \omitEnvironment specifies the environment you want to omit. You can use this macro several times to specify several environments, and all of them will be omitted. Macro \omitFileSuffix specifies the suffix that will be appended to the output filename.

Run:

$lualatex MWE.tex  And you will get two files (and all the usual auxiliar files, of course): • MWE.pdf will be generated as usually, and all the contents (including omitted environments) will be present. • MWE-sans-sol.tex is a copy of MWE.tex in which all solution environments are removed. $ diff MWE.tex MWE-sans-sol.tex
11,13d10
<   \begin{solution}
<   2. \lipsum[2]\hrulefill\par
<   \end{solution}


If you want to remove only the contents of the solution but leave the empty environment, you only have to specify \leaveEmptyEnvs at some point of MWE.tex. In this case the diff will show:

$diff MWE.tex MWE-sans-sol.tex 12d11 < 2. \lipsum[2]\hrulefill\par  PS: Thanks to Scott H. who suggested me not to use luatex callbacks, which was my first (and too convoluted) approach • ¡Muchas gracias! It works. Now I have a perfect excuse to learn LuaLaTeX. – Ignasi Mar 11 '13 at 15:07 • My first lualatex lesson: changing \directlua{dofile("remove-env.lua")} to \directlua{require("remove-env.lua")} I can have both remove-env files in my localtex folder instead of working folder. – Ignasi Mar 11 '13 at 15:35 A TeX only solution; it assumes that you don't have any other environment whose name starts with the string soluti other than solution. Prepare the following extract.tex file: \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  Change the file names as desired. Put this file along with the main file and compile with pdftex or pdflatex (it's the same). With your example file, the resulting file will be % This is main.tex file \documentclass{article} \begin{document} \begin{exercise} This is the first exercise \begin{solution} \end{solution} \end{exercise} \end{document}  Basically we read the main file line by line (ignoring category codes) with \readline; if the line starts with \begin{soluti  then we write out the line with a blank line following it and set a conditional to false; if the line starts with \end{solution  then the conditional is set again to true. The current line is written out if the conditional is true. I had the same problem. I ended up using docstrip. The system I set up produces: • (i) separate tex and pdf files for me (with solutions) and the students (without solutions:), • (ii) several versions of the exercise, for grouping students, and • (iii) typesets the only selected topic(s), allowing me to keep all the exercises in the same file. Here's the outline of the main file containing exercises and solutions: % 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}  And this is the .ins file for 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  Finally, a very badly written makefile --- nothing more than a camouflaged bash script, really. (I guess that ideally, running make should produce the .ins file automatically ... ahh, some day...) 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'  Here's an awk program that generates a TeX file with everything but the contents of solution environments, leaving those environments for students to fill in. A hack for windows follows. #!/usr/bin/awk # Filter out solution environment # BEGIN{ printing = 1; } /begin\{solution/ { print print " write your answer here" printing = 0; } printing >0 { print; } /end\{solution/ { print printing = 1; }  @HendrikVogt notes that you're on windows. This might work for you: http://gnuwin32.sourceforge.net/packages/gawk.htm Edit: A clumsy windows solution. It uses an online bash shell to save a copy of the awk program, save a copy of the TeX source, then execute the program on the source. IMPERFECTION: solution seems to eat white space at the beginning of a line. TeX wouldn't care, but users might. cat << 'EOF' > /tmp/myprog #!/usr/bin/awk BEGIN{ printing = 1;} /begin\{solution/ { print; print "your answer here"; printing = 0;} printing >0 { print} /end\{solution/ { print; printing = 1;} EOF # # paste your TeX document here cat << 'EOF' > /tmp/mytex \documentclass{article} \begin{document} Test mathematics:$e^{i\pi} = -1$. Test "double" and 'single' quotes and a *. \begin{exercise} Question here:$ 2 + 2 = ?$. \begin{solution}$4$\end{solution} \end{exercise} \end{document} EOF awk -f /tmp/myprog /tmp/mytex  Output for this test: Thanks to https://stackoverflow.com/questions/15329323/here-document-that-disables-shell-parsing for the here-document syntax to disable shell interpretation. • Please note that the OP works on Windows and doesn't look for a solution with grep and friends. (On a Unix system I'd use such an external program, too!) – Hendrik Vogt Mar 8 '13 at 15:59 • If I had access to a Windows machine, I would advise that VBS be looked into as an alternative. Installing open ports is a pain on Windows, and it's much easier to just use the built-in tools (even if far inferior) for single-purpose things like this. – Sean Allred Mar 8 '13 at 20:43 • @HendrikVogt: grep is available for Windows. There's also CygWin that provides a Unix-like interface and accompanying command-line programming functionality, including grep. – Werner Mar 9 '13 at 0:49 • Also$ in the tex could cause trouble. Imagine the document contains the formula $PWD$. – JLDiaz Mar 9 '13 at 1:36
• @JLDiaz With a here-document quotes work and  half works. Any suggestions? – Ethan Bolker Mar 9 '13 at 21:39

The simplest option is probably the extract package, mentioned by mbork in comments. However, this method will not allow you to nest your solution environment inside the exercise environment.

\documentclass{article}
\usepackage[
active,
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}


Resulting in code for the extracted file of:

\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}


I have been using answers package for this purpose. You can prepare different versions of solutions also if you want, a marking scheme, a full solution, all from the same file. The documentation has examples. Here is how I use it.

\documentclass{article}
\usepackage{answers}%Use this once the solutions are final.
\Newassociation{sol}{nothing}{ans}
\newcommand{\nothingparams}{\relax}
\begin{document}
\Opensolutionfile{ans}[mysolution-file]
\begin{Filesave}{ans}
\begin{center}
%details regarding examination etc.
\end{center}
\begin{enumerate}
\end{Filesave}
\begin{exercise}
......
\end{exercise}
\begin{sol}
.......
\end{sol}
....

\begin{Filesave}{ans}
\end{enumerate}
\end{Filesave}
\Closesolutionfile{ans}
\newpage
%\input{mysolution-file.tex}%Remove the comment after finalising.
\end{document}
`

Explanation: Everything you include between \begin{sol} and \end{sol} is written to the file mysolution-file.tex. If you choose the no solutionfiles option, the solution is printed right below the question. This is convenient while preparing questions. After finalising you can disable this line and enable the line without the option. You can also enable the \input command in the end. All the solutions are printed after the question paper. Everything between \begin{Filesave}{ans} and \end{Filesave} is saved to the file mysolution-file.tex. I use this to write information regarding the examination to the solution file. I also use them to enclose the solution in enumerate environment. Alternatively, you can write another main tex file and \include the mysolution-file.tex.

Edit I read the question again. You need a texfile with the solutions removed also. You can use extract package to produce a solution file with the portions enclosed between \begin{sol} and \end{sol} removed.