3

I am typesetting a collection of mathematical problems, solutions and notes to them in Plain TeX. The simplified document is:

\def\problem{Problem. }
\def\solution{Solution. }
\def\note{Note. }

\problem (The first problem)

\solution (Solution to the first problem)

\note (Note to the first problem)

\problem (The second problem)

\problem (The third problem)

\solution (Solution to the third problem)

Now that I want to typeset the document without the solutions and notes, only altering the first and last lines of the document (because there are quite a large number of problems).

I noticed that \iffalse can be utilized to 'comment out' blocks of content, so I had

\newif\ifproblemonly\problemonlytrue
\def\problem{Problem. \ifproblemonly\iffalse\fi}

However that does not compile (for obvious reasons: the \fi goes together with the \iffalse, rather than the \ifproblemonly). I noticed that adding a pair of curly braces (I'm not sure if {} is called so) will solve the problem.

When I rewrite the \problem again to add the \fi (that goes together with the \iffalse), I added a new count, and had something like this:

\newif\ifproblemonly\problemonlytrue
\newcount\isproblem
\def\problem{\ifproblemonly{\if\the\isproblem0{\fi}\fi}\fi Problem. \ifproblemonly{\iffalse}\fi \isproblem 1\relax}
\def\solution{Solution. \isproblem 0\relax}
\def\note{Note. \isproblem 0\relax}

and added \ifproblemonly{\if\the\isproblem0{\fi}\fi}\fi at the end of the document.

However I encountered an error 'Extra \fi' when I was trying to compile it.

My question is:

  • What is the problem here?
  • Is there a better (in some aspects) way to 'comment out' these solutions and notes?
  • How is the expansion of conditionals (\if, \ifx, \ifnum, etc.) handled in TeX?

Thanks in advance.

3
  • 1
    When TeX is skipping the false branch of a conditional it doesn't expand macros, so it cannot be conditionals in the replacement text of \solution and \note. All would be easier if you switch to a syntax such as \solution...\endsolution.
    – egreg
    Nov 6, 2021 at 14:33
  • For the last question -- I somewhat understand this thing intuitively, but a proper explanation can be found in -- The TeXBook, page 213, chapter 20: Definitions (also called Macros).
    – user202729
    Nov 6, 2021 at 16:50
  • Since you're using plain TeX, you can "isolate" the content of each problem, etc., by using a delimited definition: \def\problem (#1) {\ifproblems Problem. (#1)\fi} with an appropriate switch. Beware of nested parentheses within the text of such a delimited "argument". Nov 7, 2021 at 17:33

6 Answers 6

2

I suggest to enclose the problems section (I guess you may have other text besides them) in \problems...\endproblems.

\newif\ifsolutionsonly
\newif\ifskipping
\newbox\skipbox

\def\problems{%
  \ifsolutionsonly
    \def\problem{%
      \ifskipping\egroup\fi
      \par Problem. \ignorespaces
    }%
    \def\solution{\ifskipping\else\setbox\skipbox=\vbox\bgroup\skippingtrue\fi}
    \let\note\solution
  \else
    \def\problem{Problem. \ignorespaces}
    \def\solution{Solution. \ignorespaces}
    \def\note{Note. \ignorespaces}
  \fi
}
\def\endproblems{\ifskipping\egroup\fi}


\problems
\problem (The first problem)

\solution (Solution to the first problem)

\note (Note to the first problem)

\problem (The second problem)

\problem (The third problem)

\solution (Solution to the third problem)
\endproblems

\bigskip

\solutionsonlytrue

\problems
\problem (The first problem)

\solution (Solution to the first problem)

\note (Note to the first problem)

\problem (The second problem)

\problem (The third problem)

\solution (Solution to the third problem)
\endproblems

\bye

In case \ifsolutionsonly returns true, \solution and \note will start typesetting in a box that will be discarded, whereas \problem will stop the box being built (and it will be discarded). At the end \endproblems will take care of a possible box still being typeset.

enter image description here

On the other hand, a syntax such as

\problem
(The first problem)
\endproblem

\solution
(Solution to the first problem)
\endsolution

\note
(Note to the first problem)
\endnote

\problem
(The second problem)
\endproblem

\problem
(The third problem)
\endproblem

\solution
(Solution to the third problem)
\endsolution

would be much easier to manage.

1

The following works as long as you end your file with \bye. It works by setting \solution and \note to gobble everything up to the next call of \problem, \endgobble (a special marker that doesn't produce output, only provided for convenience), or \bye. This will not be particularly fast though, but shouldn't require any change to your file (except maybe adding \bye to the end).

\newif\ifproblemonly\problemonlytrue

\def\problem{Problem. }
\ifproblemonly
  \def\solution{\gobblesolutionandnote}
  \def\note{\gobblesolutionandnote}
\else
  \def\solution{Solution. }
  \def\note{Note. }
\fi

\def\endgobble{\gobble{\endgobble}}% <- arbitrary end flag that doesn't produce output
\long\def\firstofone#1{#1}
\long\def\gobbletwo#1#2{}
\long\def\gobble#1{}
\long\def\ifnextnot#1{\ifx\next#1\expandafter\gobbletwo\fi\firstofone}
\long\def\ifnextnotbye{\expandafter\ifx\csname bye\endcsname\next\expandafter\gobbletwo\fi\firstofone}
\def\gobblesolutionandnote
  {%
    \afterassignment\gobblesolutionandnoteAUX
    \let\next=
  }
\def\gobblesolutionandnoteAUX
  {%
    \ifnextnot\problem
      {%
        \ifnextnot\endgobble
          {\ifnextnotbye{\expandafter\gobblesolutionandnote\gobble}}%
      }%
    \next
  }

\problem (The first problem)

\solution (Solution to the first problem)

\note (Note to the first problem)

\problem (The second problem)

\problem (The third problem)

\solution (Solution to the third problem)

\bye
1

Rather than answer the question about \if...\fi workings, I would approach the problem differently. By enabling the alternate definitions between the % lines, the solutions and notes are excluded.

\def\problem#1{Problem. #1}
\def\solution#1{Solution. #1}
\def\note#1{Note. #1}
%
\def\solution#1{}
\def\note#1{}
%

\problem {(The first problem)}

\solution {(Solution to the first problem)}

\note {(Note to the first problem)}

\problem {(The second problem)}

\problem {(The third problem)}

\solution {(Solution to the third problem)}

\bye

enter image description here

If I comment out the two lines of redefinition, I get the full result:

enter image description here

8
  • I doubt that the OP would use () to delimit the actual texts.
    – egreg
    Nov 6, 2021 at 15:45
  • \problem (this (may) be a problem) Nov 6, 2021 at 15:47
  • @DavidCarlisle okay, okay. I went the normal brace route. Nov 6, 2021 at 15:49
  • @egreg Revised to avoid David's shortcoming. Nov 6, 2021 at 15:49
  • 2
    are you saying I have shortcomings ? :( Nov 6, 2021 at 15:53
1

You would not want

\ifproblemonly\iffalse\fi

but simply

\ifproblemonly

if this is false everything would be skipped until the matching \fi but this would have to be literally in the document, not inside a macro.

I don't think you need conditionals at all here inside your commands.

just something like

\newif\ifproblemonly
\problemonlytrue % or false

\ifproblemonly
  \long\def\problem#1{Problem. #1\par}
  \long\def\solution#1{}% gobble solution
  \long\def\note#1{}% gobble note
\else
  \long\def\problem#1{Problem. #1\par}
  \long\def\solution#1{Solution. #1\par}
  \long\def\note#1{Note. #1\par}
\fi

so your test document

\newif\ifproblemonly
\problemonlytrue % or false

\ifproblemonly
\def\problem#1{Problem. #1\par}
\def\solution#1{}% gobble solution
\def\note#1{}% gobble note
\else
\def\problem#1{Problem. #1\par}
\def\solution#1{Solution. #1\par}
\def\note#1{Note. #1\par}
\fi

\problem {The first problem}

\solution {Solution to the first problem}

\note {Note to the first problem}

\problem {The second problem}

\problem {The third problem}

\solution {Solution to the third problem}

\bye

produces

enter image description here

or

enter image description here

3
  • I changed \problem and friends to use {} delimted argument not () you could use an argument delimted as (#1) but then any parenthesis within the problem text woul dneed to be hidden inside braces. Nov 6, 2021 at 15:20
  • Sorry but I forgot to mention that the problems, solutions and notes can span multiple paragraphs, so the curly braces won't work...Thanks, though.
    – Vursc
    Nov 7, 2021 at 3:00
  • @Vursc just use \long\def to allow paragraphs (I'll add to the answer) You didn't only not mention it you provided a test file with definitions of \problem and \solution that were not \long so also explicitly did not allow paragraphs. Nov 7, 2021 at 9:07
1

I can offer a macro \GobbleTillProblemOrContinueOrBye which within a local scope switches catcodes of { and } to 12 and makes \bye non-outer and - if the \meaning of \everyeof yields the string \everyeof and thus denotes an existing primitive - sets \everyeof{\continue} and then calls a macro \Gobbleloop which tail-recursively gobbles tokens until the token currently processed either is the control-word-token \problem or the control-word-token \continue or the control-word-token \bye in which case the local scope is closed and the token in question is delivered.

You can have the commands \solution and \note call this macro in case you want to print problems only.

Notice that the implementation internally does without any \if..-conditional but the switch \ifproblemonly requested by the questioner.

Be aware:

  • \input-commands occurring in notes/solutions are not carried out if only problems are to be printed.

  • \endinput-commands occurring in notes/solutions are not carried out, too, if only problems are to be printed.

  • In case of e-TeX-extensions/\everyeof not being available \Gobbleloop does not check whether the end of the file is reached.

Thus: Files processed with engines where \everyeof of the e-TeX-extensions is not available and not ending with the control-word-token \bye should end with the control-word-token \continue, probably trailed by \endinput or whatever command you use for terminating the processing of the file/the .tex-document.

Otherwise, if only problems are to be printed, the routine \Gobbleloop for gobbling things might deliver an error-message about unexpected end of file.

%%=============================================================================
%% Toggle: problem only -- also solutions/notes
%%.............................................................................
\newif\ifproblemonly
\problemonlytrue
%\problemonlyfalse
%%=============================================================================
%% PARAPHERNALIA:
%% \UDfirstoftwo, \UDsecondoftwo, \UDExchange, \UDstopromannumeral, 
%% \UDgobbletoexclam, \UDCheckWhetherNull,
%%-----------------------------------------------------------------------------
\long\def\UDfirstoftwo#1#2{#1}%
\long\def\UDsecondoftwo#1#2{#2}%
\long\def\UDExchange#1#2{#2#1}%
\chardef\UDstopromannumeral=`\^^00%
\long\def\UDgobbletoexclam#1!{}%
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \UDCheckWhetherNull{<Argument which is to be checked>}%
%%                    {<Tokens to be delivered in case that argument
%%                      which is to be checked is empty>}%
%%                    {<Tokens to be delivered in case that argument
%%                      which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\long\def\UDCheckWhetherNull#1{%
  \romannumeral\expandafter\UDsecondoftwo\string{\expandafter
  \UDsecondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \UDsecondoftwo\string}\expandafter\UDfirstoftwo\expandafter{\expandafter
  \UDsecondoftwo\string}\expandafter\UDstopromannumeral\UDsecondoftwo}{%
  \expandafter\UDstopromannumeral\UDfirstoftwo}%
}%
%%-----------------------------------------------------------------------------
%% \Gobbleloop
%%.............................................................................
\let\savedbye=\bye
\edef\bye{\noexpand\bye}%
\def\neutralizebye{\edef\bye{\noexpand\bye}}%
\long\def\Gobbleloop#1{%
  \expandafter\UDCheckWhetherNull\expandafter{\UDgobbletoexclam#1!}%
  {%
    \ByeContinueProblemFork
    !#1!\continue!\problem!{\endgroup#1}%
    !\bye!#1!\problem!{\endgroup#1}%
    !\bye!\continue!#1!{\endgroup#1}%
    !\bye!\continue!\problem!{\Gobbleloop}%
    !!!!%
  }{\Gobbleloop}%
}%
\long\def\ByeContinueProblemFork#1!\bye!\continue!\problem!#2#3!!!!{#2}%
%%.............................................................................
%% \everyeoffork is needed to check the meaning of \everyeof
%%.............................................................................
\expandafter\def\expandafter\everyeoffork\expandafter#%
\expandafter1\expandafter$\string\everyeof$#2#3$$${#2}%
%%.............................................................................
%% Macro to initiate \Gobbleloop depending on \if...-switch:
%%.............................................................................
\def\GobbleTillProblemOrContinueOrBye#1{%
  \ifproblemonly
    \begingroup\catcode`\{=12 \catcode`\}=12 \neutralizebye
    %%.........................................................................
    % In case \everyeof is defined to be the \everyeof-primitive, i.e., in
    % case \meaning\everyeof yields the string \everyeof, do
    % \everyeof{\continue} for handling the case of reaching the end of a file
    \expandafter\UDExchange\expandafter{\string\everyeof${}}%
    {\expandafter\everyeoffork\expandafter$\meaning\everyeof$%
     {\everyeof{\continue}}$}$$$%
    %%.........................................................................
    \expandafter\Gobbleloop
  \else#1. \fi
}%
\let\bye=\savedbye
\let\savedbye\UnDeFineD
%%=============================================================================
\def\problem{Problem. }%
\def\solution{\GobbleTillProblemOrContinueOrBye{Solution}}%
\def\note{\GobbleTillProblemOrContinueOrBye{Note}}%
\def\continue{}%
%%=============================================================================

\problem  
(The first problem)

\solution (Solution to the first problem)

\note (Note to the first problem)

\problem (The second problem)

\problem (The third problem)

\solution (Solution to the third problem)

\continue (something that shall occur in any case although it is not a problem)

\note (Note to the third problem)

\problem % some comment
(The fourth problem)

\solution (Solution to the fourth problem)

\bye

This is what you get with \problemonlyfalse:

enter image description here

This is what you get with \problemonlytrue:

enter image description here



If you like really complicated code suitable not only for detecting single control-word-tokens but suitable for detecting phrases consisting of several tokens I can offer a routine \GobbleTillProblemOrSolutionOrNoteOrContinueOrBye which switches to verbatim-catcode-régime and by means of accumulating characters and checking by means of delimited arguments gobbles everything until finding one of the phrases \problem⟨space⟩ / \problem⟨carriage return⟩ / \continue⟨space⟩ / \continue⟨carriage return⟩ / \bye⟨space⟩ / \bye⟨carriage return⟩.

!!! A trailing/separating ⟨space⟩ or ⟨carriage return⟩ must be present!!!

E.g. \continue\relax is not taken for a marker for terminating the gobbling-loop.
E.g. \continue% is not taken for a marker for terminating the gobbling-loop.
But with \continue⟨space⟩\relax, i.e., with \continue \relax, the sequence \continue⟨space⟩ is taken for a marker that terminates the gobbling-loop.

You can have the command \solution or \note call this routine in case you want to print problems only.

You can omit scanning for \solution⟨space⟩ / \solution⟨carriage return⟩ and \note⟨space⟩ / \note⟨carriage return⟩ in case of printing problems only because in this case these just initiate more gobbling.
I decided to add scanning for these commented out so you can more easily introduce more \if-switches, e.g., for printing notes as well but not printing solutions or for printing solutions as well but not printing notes, where scanning for these would be needed.

%%=============================================================================
%% Toggle: problem only -- also solutions/notes
%%.............................................................................
\newif\ifproblemonly
\problemonlytrue
%\problemonlyfalse
%%=============================================================================
%% PARAPHERNALIA:
%% \UDfirstoftwo, \UDsecondoftwo, \UDExchange, \UDstopromannumeral, 
%% \UDgobbletoexclam, \UDCheckWhetherNull,
%%-----------------------------------------------------------------------------
\long\def\UDfirstoftwo#1#2{#1}%
\long\def\UDsecondoftwo#1#2{#2}%
\long\def\UDExchange#1#2{#2#1}%
\chardef\UDstopromannumeral=`\^^00%
\long\def\UDgobbletoexclam#1!{}%
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \UDCheckWhetherNull{<Argument which is to be checked>}%
%%                    {<Tokens to be delivered in case that argument
%%                      which is to be checked is empty>}%
%%                    {<Tokens to be delivered in case that argument
%%                      which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\long\def\UDCheckWhetherNull#1{%
  \romannumeral\expandafter\UDsecondoftwo\string{\expandafter
  \UDsecondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \UDsecondoftwo\string}\expandafter\UDfirstoftwo\expandafter{\expandafter
  \UDsecondoftwo\string}\expandafter\UDstopromannumeral\UDsecondoftwo}{%
  \expandafter\UDstopromannumeral\UDfirstoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Scratch-macros for defining final version of \Gobbleloop
%%.............................................................................
\def\Gobbleloop#1#2#3{%
  % #1: definition-text/(sub-)phrase-checks of final \Gobbleloop
  %     accumulated so far.
  % #2: <phrase> whose matching-check is to be defined and 
  %     appended to #1 this time.
  % #3: emptiness or tokens to carry out in case characters
  %     gathered match <phrase>.
  \UDCheckWhetherNull{#2}{\def\Gobbleloop##1##2{#1}}{%
      \csname\string\fork\expandafter\endcsname
      \csname#2fork\expandafter\endcsname
      \csname fork#2\endcsname
      {#3}{#2}{#1}%
  }%
}%
\expandafter\def\csname\string\fork\expandafter\endcsname#1#2#3#4#5{%
  % #1: \<phrase>fork - 1st macro-token of mechanism forming 
  %     matching-check for <phrase>
  % #2: \fork<phrase> - 2nd macro-token of mechanism forming 
  %     matching-check for <phrase>
  % #3: emptiness or tokens to carry out in case characters
  %     gathered match <phrase>.
  % #4: <phrase> whose matching-check is to be defined and 
  %     appended to #1 this time.
  % #5: definition-text/(sub-)phrase-checks of final \Gobbleloop
  %     accumulated so far.
  \def#1##1{%
    \expandafter\UDCheckWhetherNull\expandafter{\UDgobbletoexclam##1!}%
    {#2!##1!{\UDfirstoftwo}!#4!{\UDsecondoftwo}!!!!}{\UDsecondoftwo}%
  }\long\def#2##1!#4!##2##3!!!!{##2}%
  \UDCheckWhetherNull{#3}{%
    \Gobbleloop{#1{##1##2}{\Gobbleloop{#4}}{#5}}%
  }{%
    \Gobbleloop{#1{##1##2}{\endgroup#3}{#5}}%
  }%
}%
%%.............................................................................
%% \everyeoffork is needed to check the meaning of \everyeof
%%.............................................................................
\expandafter\def\expandafter\everyeoffork\expandafter#%
\expandafter1\expandafter$\string\everyeof$#2#3$$${#2}%
%%.............................................................................
%% Change the catcode-régime for defining final version of \Gobbleloop
%% and call the scratch-\Gobbleloop for defining the final \Gobbleloop
%%.............................................................................
\catcode`\/=0\relax%
\catcode`\^^M=12\relax%
\catcode`\ =12\relax%
\catcode`\!=14\relax%
\catcode`\%=12\relax!
\catcode`\\=12/relax!
/def/continuephrase{\continue }!
!! The scratch-\Gobbleloop recursively iterates over 2-tuples of arguments
!! for defining the final \Gobbleloop.
!! The 1st component of such a 2-tuple s the character-sequence forming the
!!    (sub-)phrase to be matched.
!! The 2nd component is the tokens to carry out after terminating the loop
!!    in case of match.
!! The final \Gobbleloop recursively gathers characters one by one from
!!    the input and compares the characters gathered in previous iterations 
!!    plus the character gathered in this iteration to each (sub-)phrase.
!! If a match occurs and with that match the second component of the
!!    corresponding 2-tuple is not empty, the loop terminates and delivers 
!!    the tokens comeing from the 2nd component of the corresponding 2-tuple.
!! If a match occurs and with that match the second component of the
!!    corresponding 2-tuple is empty, the loop continues with the matching
!!    phrase forming the characters gathered so far.
!! If no match occurs, the loop continues with characters gathered so far
!!    being empty.
/Gobbleloop{/Gobbleloop{}}!
!..............................................................................
! If you want \Gobbleloop to terminate when finding \note<return> or 
! \note<space> and to call \note:
!{\note^^M}{note}{\note }{note}{\note}{}{\not}{}{\no}{}{\n}{}!
!..............................................................................
! If you want \Gobbleloop to terminate when finding \solution<return> or
! \solution<space> and to call \solution:
!{\solution^^M}{/solution}{\solution }{/solution}!
!{\solution}{}{\solutio}{}{\soluti}{}{\solut}{}{\solu}{}{\sol}{}{\so}{}{\s}{}!
!..............................................................................
! If you want \Gobbleloop to terminate when finding \bye<return> or 
! \bye<space> and to call \bye:
{\bye^^M}{/csname/UDfirstoftwo{}{}bye/endcsname}!
{\bye }{/csname/UDfirstoftwo{}{}bye/endcsname}{\bye}{}{\by}{}{\b}{}!
!..............................................................................
! If you want \Gobbleloop to terminate when finding \continue<return> or
! \continue<space> and to call \continue:
{\continue^^M}{/continue}{\continue }{/continue}!
{\continue}{}{\continu}{}{\contin}{}{\conti}{}{\cont}{}{\con}{}{\co}{}{\c}{}!
!..............................................................................
! If you want \Gobbleloop to terminate when finding \problem<return> or
! \problem<space> and to call \problem
{\problem^^M}{/problem}{\problem }{/problem}{\problem}{}!
{\proble}{}{\probl}{}{\prob}{}{\pro}{}{\pr}{}{\p}{}!
!..............................................................................
! Scan for the backslash:
{\}{}!
! ( When scanning for more (sub-)phrases you need to add tuples 
!   only for those (sub-)phrases that are not already in the
!   2-tuple-list. )
! Scanning for the backslash must be the last item of the 2-tuple
! list before the terminating-tuple because this overrides the
! scratch-definition of the \\fork-macro.
!
! This is the tuple terminating the recursion of the scratch-\Gobbleloop -
! emptiness as sub-phrase to match would not make sense:
{}{}!
!!.............................................................................
!! Reset the catcode-régime:
!!.............................................................................
/catcode`/\=0/relax!
\catcode`\%=14\relax!
\catcode`\!=12\relax%
\catcode`\ =10\relax%
\catcode`\^^M=5\relax%
\catcode`\/=12\relax%
%%.............................................................................
%% Macro to switch catcode-régime and to call \Gobbleloop
%%.............................................................................
\def\InitiateGobbleloop{%
  \begingroup
  \catcode`\^^M=12 \catcode`\ =12 \catcode`\\=12 \catcode`\{=12 \catcode`\}=12 %
  \catcode`\$=12 \catcode`\&=12 \catcode`\#=12 \catcode`\^=12 \catcode`\_=12 %
  \catcode`\~=12 % \catcode`\%=12 %
  %%.........................................................................
  % In case \everyeof is defined to be the \everyeof-primitive, i.e., in
  % case \meaning\everyeof yields the string \everyeof, do
  % \everyeof{\continue} for handling the case of reaching the end of a file
  \expandafter\UDExchange\expandafter{\string\everyeof${}}%
  {\expandafter\everyeoffork\expandafter$\meaning\everyeof$%
   {\everyeof\expandafter{\continuephrase}}$}$$$%
  %%.........................................................................
  \Gobbleloop{}%
}%
%%.............................................................................
%% Macro to initiate \Gobbleloop depending on \if...-switch:
%%.............................................................................
\def\GobbleTillProblemOrSolutionOrNoteOrContinueOrBye#1{%
  \ifproblemonly
    \expandafter\InitiateGobbleloop
  \else
    #1. \ignorespaces\expandafter\noexpand
  \fi
}%
%%=============================================================================
\def\problem{Problem. \ignorespaces\noexpand}%
\def\solution{\GobbleTillProblemOrSolutionOrNoteOrContinueOrBye{Solution}}%
\def\note{\GobbleTillProblemOrSolutionOrNoteOrContinueOrBye{Note}}%
\def\continue{\ignorespaces\noexpand}%
%%=============================================================================

\problem  
(The first problem)

\solution (Solution to the first problem)

\note (Note to the first problem)

\problem (The second problem)

\problem (The third problem)

\solution (Solution to the third problem)

\continue (something that shall occur in any case although it is not a problem)

\note (Note to the third problem)

\problem % some comment
(The fourth problem)

\solution (Solution to the fourth problem)

\bye

This is what you get with \problemonlyfalse:

enter image description here

This is what you get with \problemonlytrue:

enter image description here

Notice that the implementation internally does without any \if..-conditional but the switch \ifproblemonly requested by the questioner.



With both examples you can easily modify the code so that the gobbling-routine also stops when finding \input or \endinput.

If you do this I suggest having copies of \input and \endinput via \let\noteinput=\input/\let\solutioninput=\input and \let\noteendinput=\endinput/\let\solutionendinput=\endinput where gobbling will not be stopped so that these are carried out only if not only problems but solutions/notes as well are produced. These can be used for inputting files whose entire content belongs to a solution or a note only where the corresponding \noteinput-/\solutioninput-command occurs.

0

How about using docstrip, introducing tags for marking what goes where?

%<*ignore>
\begingroup
\input docstrip
\generate{%
  \nopreamble
  \nopostamble
  \file{\jobname ProblemsOnly.tex}{\from{\jobname.tex}{problem}}%
  \file{\jobname ProblemsSolutionsNotes.tex}{\from{\jobname.tex}{problem,solution,note}}%
}%
% Here you can probably insert \write18-calls suitable for your platform
% for calling tex/pdftex from console for compiling the files
% just generated.
%
%\immediate\write18{pdftex \jobname ProblemsOnly.tex}%
%\immediate\write18{pdftex \jobname ProblemsSolutionsNotes.tex}%
%
% If you wish these \write18-calls to work out, this file needs to
% be compiled using the commandline-option --shell-escape
% or the commandline-option --enable-write18
% , i. e.,  pdftex --shell-escape test.tex
%, or pdftex --enable-write18 test.tex
%
% If the real-life-scenario is about LaTeX, probably using a
% LuaTeX-engine, have a look at the shellesc-package and in the
% <*ignore>..</ignore>-section use \stop instead of \bye.
%
\endgroup
\bye
%</ignore>
%<*problem>

Problem.  (The first problem)
%</problem>
%<*solution>

Solution. (Solution to the first problem)
%</solution>
%<*note>

Note. (Note to the first problem)
%</note>
%<*problem>

Problem. (The second problem)

Problem. (The third problem)
%</problem>
%<*solution>

Solution. (Solution to the third problem)
%</solution>

(something that shall occur in any case)
%<*note>

Note. (Note to the third problem)
%</note>
%<*problem>

Problem. (The fourth problem)
%</problem>
%<*solution>

Solution. (Solution to the fourth problem)
%</solution>
\bye

The example above generates two new files. If it is saved as test.tex, the new files will be testProblemsOnly.tex and testProblemsSolutionsNotes.tex.

The content of testProblemsOnly.tex is:


Problem.  (The first problem)

Problem. (The second problem)

Problem. (The third problem)

(something that shall occur in any case)

Problem. (The fourth problem)
\bye

Compiling testProblemsOnly.tex yields an output file with the following content:

enter image description here

The content of testProblemsSolutionsNotes.tex is:


Problem.  (The first problem)

Solution. (Solution to the first problem)

Note. (Note to the first problem)

Problem. (The second problem)

Problem. (The third problem)

Solution. (Solution to the third problem)

(something that shall occur in any case)

Note. (Note to the third problem)

Problem. (The fourth problem)

Solution. (Solution to the fourth problem)
\bye

Compiling testProblemsSolutionsNotes.tex yields an output file with the following content:

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .