
Ich versuche, mir ein Paket ähnlich dem Übungspaket zu schreiben, damit ich Aufgabensätze für meine Studenten vorbereiten kann. Ich möchte die Ausgabe von Aufgaben und/oder Lösungen verzögern, bis eine geeignete Stelle im Dokument erreicht ist. Ich habe etwas, das einigermaßen funktioniert, aber es ist etwas klobig. Das hier funktioniert zum Beispiel ziemlich gut:
\usepackage{environ}
\NewEnviron{testb}{\global\expandafter\let\csname bar\endcsname\BODY}
Ich verwende \csname
, weil die Namen dynamisch generiert werden. Das funktioniert nicht so gut, wenn der Befehl etwas anderes als ist \BODY
. Wenn ich beispielsweise verwende \let\bar{\BODY}
, hat Latex ein Aneurysma (es bindet \bar
nur an {).
Es gibt hierfür eine alternative Möglichkeit:
\NewEnviron{testc}{\global\expandafter\edef\csname foo\endcsname{\BODY}}
Das funktioniert irgendwie. Folgendes funktioniert:
\begin{testc}hi\end{testc}
, aber das verursacht ein Aneurysma bei LaTeX: \begin{testc}\bf hi\end{testc}
. (Die Fehlermeldung lautet ). Ich habe versucht, es selbst zu debuggen, aber ich verheddere mich hoffnungslos in Paketen, die ich nicht verstehe. Wenn Sie es mit anstelle von \incomplete
tun, erhalten Sie die völlig andere LaTeX-Fehlermeldung:\tiny
\bf
! TeX capacity exceeded, sorry [input stack size=5000].
\BODY
Wie kann ich nicht nur , sondern eine ausgeklügelte Kombination aus und anderen Dingen für später zurücklegen \BODY
und gleichzeitig dafür sorgen, dass es gegenüber dem, was zwischen Anfang und Ende liegt, robust bleibt?
Bearbeiten: ok, mehrere Lösungen unten
Antwort1
Mit \unexpanded
können Sie sich Sorgen über ersparen \protected@xdef
.
\documentclass{article}
\usepackage{environ}
\NewEnviron{exercise}{%
\xdef\savedexercises{%
\unexpanded\expandafter{\savedexercises}%
\noexpand\begin{printedexercise}%
\unexpanded\expandafter{\BODY}%
\noexpand\end{printedexercise}%
}%
}
\newcommand{\printexercises}{%
\savedexercises
\gdef\savedexercises{}%
}
\newcommand{\savedexercises}{}
\newtheorem{printedexercise}{Exercise}
\begin{document}
Here we talk about addition and show that $1+1=2$.
\begin{exercise}
Compute $1+2$
\end{exercise}
Here we talk about integrals.
\begin{exercise}
Compute the following integrals:
\begin{itemize}
\item $\displaystyle\int_0^x e^{-t^2}\,dt$
\item $\displaystyle\int_1^x \frac{e^t}{t}\,dt$, for $t>0$.
\end{itemize}
\end{exercise}
Now we can print the exercises.
\printexercises
\end{document}
Ich habe es \newtheorem
nur als Beispiel verwendet.
Mit xparse
der Veröffentlichung vom 05.03.2019 oder später:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentEnvironment{exercise}{+b}
{
\tl_gput_right:Nn \g_loisel_exercises_tl
{
\begin{printedexercise}
#1
\end{printedexercise}
}
}{}
\NewDocumentCommand{\printexercises}{}
{
\tl_use:N \g_loisel_exercises_tl
\tl_gclear:N \g_loisel_exercises_tl
}
\tl_new:N \g_loisel_exercises_tl
\ExplSyntaxOff
\newtheorem{printedexercise}{Exercise}
\begin{document}
Here we talk about addition and show that $1+1=2$.
\begin{exercise}
Compute $1+2$
\end{exercise}
Here we talk about integrals.
\begin{exercise}
Compute the following integrals:
\begin{itemize}
\item $\displaystyle\int_0^x e^{-t^2}\,dt$
\item $\displaystyle\int_1^x \frac{e^t}{t}\,dt$, for $t>0$.
\end{itemize}
\end{exercise}
Now we can print the exercises.
\printexercises
\end{document}
Antwort2
Wenn Sie BODY
sparen und dann dynamisch Dinge hinzufügen möchten, verwenden Sie am besten zwei Makros:
\documentclass{article}
\usepackage{environ}
\NewEnviron{testb}{%
\global\expandafter\let\csname bar\endcsname\BODY
\expandafter\xdef\csname barplus\endcsname{%
\expandafter\noexpand\csname bar\endcsname
\noexpand\bf Hi
}%
}
\begin{document}
\begin{testb}
\bfseries
Hi
\end{testb}
\show\barplus
\end{document}
Wenn Sie die Verwendung vermeiden möchten, \BODY
können Sie verwendenxparse
\documentclass{article}
\usepackage{xparse}
\NewDocumentEnvironment{testb}{+b}{\expandafter\gdef\csname bar\endcsname{#1}}{}
\begin{document}
\begin{testb}
\bfseries
Hi
\end{testb}
\show\bar
\end{document}
Antwort3
Ein Trick zum Auslösen der Erweiterung ist die Verwendung von \romannumeral
:
Wenn aufgrund von \romannumeral
(La)TeX eine Ziffernfolge mit anschließendem Leerzeichen als Zahl erstellt wird, die es umwandeln muss, werden erweiterbare Token erweitert.
Kommt am Ende eine Zahl zusammen, die nicht positiv ist, so wird (La)TeX als Ergebnis der Konvertierung keinerlei Token liefern.
Man kann es also gut (missbrauchen), \romannumeral
um eine Menge Erweiterungsarbeit und Argumentumkehrarbeit auszulösen, solange man sicherstellt, dass am Ende \romannumeral
keine positive Zahl herauskommt.
Hier ist eine Variante vonegregs Antwortwas mit \romannumeral
und \exchange
anstelle von \xdef
und erfolgt \unexpanded
.
\documentclass{article}
\usepackage{environ}
\newcommand\exchange[2]{#2#1}
\NewEnviron{exercise}{%
\expandafter\gdef\expandafter\savedexercises\expandafter{%
\romannumeral0\expandafter\exchange\expandafter{\BODY}{%
\exchange{ }{\expandafter}\savedexercises
\begin{printedexercise}%
}%
\end{printedexercise}%
}%
}
\newcommand{\printexercises}{%
\savedexercises
\gdef\savedexercises{}%
}
\newcommand{\savedexercises}{}
\newtheorem{printedexercise}{Exercise}
\begin{document}
Here we talk about addition and show that $1+1=2$.
\begin{exercise}
Compute $1+2$
\end{exercise}
Here we talk about integrals.
\begin{exercise}
Compute the following integrals:
\begin{itemize}
\item $\displaystyle\int_0^x e^{-t^2}\,dt$
\item $\displaystyle\int_1^x \frac{e^t}{t}\,dt$, for $t>0$.
\end{itemize}
\end{exercise}
Now we can print the exercises.
\printexercises
\end{document}
Wenn Sie den Namen des zu definierenden Makros in \csname
.. einschließen möchten, also anstelle \endcsname
von verwenden möchten , können Sie sich die Tatsache zunutze machen, dass (La)TeX erweiterbare Tokens erweitert, indem es den Namen eines Steuersequenz-Tokens erfasst und hiermit nach dem passenden sucht :\csname savedexercises\endcsname
\savedexercises
\csname
\endcsname
\documentclass{article}
\usepackage{environ}
\newcommand\exchange[2]{#2#1}
\NewEnviron{exercise}{%
\expandafter\gdef\csname savedexercises\expandafter\endcsname\expandafter{%
\romannumeral0\expandafter\exchange\expandafter{\BODY}{%
\exchange{ }{\expandafter\expandafter\expandafter}\csname savedexercises\endcsname
\begin{printedexercise}%
}%
\end{printedexercise}%
}%
}
\newcommand{\printexercises}{%
\csname savedexercises\endcsname
\expandafter\gdef\csname savedexercises\endcsname{}%
}
\expandafter\newcommand\expandafter{\csname savedexercises\endcsname}{}
\newtheorem{printedexercise}{Exercise}
\begin{document}
Here we talk about addition and show that $1+1=2$.
\begin{exercise}
Compute $1+2$
\end{exercise}
Here we talk about integrals.
\begin{exercise}
Compute the following integrals:
\begin{itemize}
\item $\displaystyle\int_0^x e^{-t^2}\,dt$
\item $\displaystyle\int_1^x \frac{e^t}{t}\,dt$, for $t>0$.
\end{itemize}
\end{exercise}
Now we can print the exercises.
\printexercises
\end{document}
Beachten Sie, dass Sie mit den bisher vorgestellten Ansätzen nicht \printexercises
an beliebigen Stellen Übungen einfügen können. Sie können Übungen nur an Stellen des Dokuments einfügen, die in der Quelle den Stellen hinter den Übungsumgebungen entsprechen.
Vielleicht eine Umgebung, die ihren Inhalt unter dem Verbatim-Catcode-Regime liest, um ihn nicht erweitert in eine .aux-Datei zu schreiben, und zwar auf eine Weise, bei der er aus der .aux-Datei unter dem Verbatim-Catcode-Regime auch zum Definieren eines Makros zurückgelesen wird \scantokens
, auf das es angewendet wird, und somit eine Art Neuimplementierung des \label
-Mechanismus \ref
oder des \tableofcontents
-Mechanismus für verbatimiertes Material, die es möglich machen könnte, Übungen im gesamten Dokument druckbar zu machen.
Die Implementierung eines solchen Mechanismus könnte eine schöne Herausforderung sein. Doch bevor man das überhaupt in Betracht zieht, sind genaue Informationen über den beabsichtigten Einsatzzweck und die gewünschte „Benutzeroberfläche“ erforderlich, d. h., welche zusätzlichen Dinge Sie auf welche Weise angeben möchten usw. ...
Antwort4
Eine weitere Variante ist die Verwendung von filecontentsdef v1.4
, Unterstützt verbatim
Inhalte (falls erforderlich).
\documentclass{article}
\usepackage{filecontentsdef,pgffor}
\setlength{\parindent}{0pt}
\pagestyle{empty}
\newtheorem{exercise}{Exercise}
% savedexercise
\newcounter{exeNr}
\newenvironment{savedexercise}
{\stepcounter{exeNr}%
\begingroup
\filecontentsdefmacro{exercise-\the\value{exeNr}}}%
{\endfilecontentsdefmacro\endgroup}
\newcommand{\printexercise}[1]{\filecontentsexec{exercise-\the\numexpr#1\relax}}
\newcommand{\printsrcexercise}[1]{\filecontentsprint{exercise-\the\numexpr#1\relax}}
\begin{document}
\section{Talk about math}
Here we talk about addition and show that $1+1=2$.
\begin{savedexercise}
Compute $1+2$
\end{savedexercise}
Here we talk about integrals.
\begin{savedexercise}
Compute the following integrals:
\begin{itemize}
\item $\displaystyle\int_0^x e^{-t^2}\,dt$
\item $\displaystyle\int_1^x \frac{e^t}{t}\,dt$, for $t>0$.
\end{itemize}
\end{savedexercise}
\section{The exercises}
Now we can print the exercises.
\foreach \i in {1,...,2} {
\begin{exercise}
\printexercise{\i}
\end{exercise}
}
\section{The src exercises}
Now we can print the src of exercises.
\foreach \i in {1,...,2} {
\printsrcexercise{\i}
}
\section{Back to first exercises}
Remember the first exercise
\setcounter{exercise}{0}
\begin{exercise}
\printexercise{1}
\end{exercise}
\end{document}