
Estou tentando escrever um pacote para mim, semelhante ao pacote de exercícios, para poder preparar conjuntos de problemas para meus alunos. Desejo adiar a saída de problemas e/ou soluções até que um local adequado no documento seja alcançado. Eu tenho algo que funciona, mas é meio desajeitado. Por exemplo, isso funciona muito bem:
\usepackage{environ}
\NewEnviron{testb}{\global\expandafter\let\csname bar\endcsname\BODY}
Eu uso \csname
porque os nomes são gerados dinamicamente. Isso não funciona tão bem se o comando for diferente de \BODY
. Por exemplo, se eu fizer isso \let\bar{\BODY}
, o látex tem um aneurisma (ele se liga \bar
apenas a {).
Existe uma maneira alternativa de fazer isso, que é:
\NewEnviron{testc}{\global\expandafter\edef\csname foo\endcsname{\BODY}}
Esse tipo de coisa funciona. A seguinte coisa funciona:
\begin{testc}hi\end{testc}
, mas isso dá ao LaTeX um aneurisma: \begin{testc}\bf hi\end{testc}
. (A mensagem de erro é \incomplete
). Tentei depurar sozinho, mas fico irremediavelmente preso em pacotes que não entendo. Se você fizer isso \tiny
em vez de, \bf
receberá uma mensagem de erro LaTeX totalmente diferente:! TeX capacity exceeded, sorry [input stack size=5000].
Como posso guardar para mais tarde, não apenas \BODY
, mas alguma combinação sofisticada de \BODY
e outras coisas, ao mesmo tempo em que é robusto para o que está entre o início e o fim?
Editar: ok, várias soluções abaixo
Responder1
Com \unexpanded
você você pode evitar se preocupar \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}
Usei \newtheorem
apenas para exemplo.
Com xparse
lançamento em 05/03/2019 ou posterior:
\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}
Responder2
Se você deseja BODY
ser salvo e adicionar coisas dinamicamente, provavelmente é melhor usar duas macros:
\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}
Se você quiser evitar o uso, \BODY
você pode usarxparse
\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}
Responder3
Um truque para acionar a expansão é usar \romannumeral
:
Quando devido ao \romannumeral
(La)TeX reúne uma sequência de dígitos seguidos por um espaço como o número que deve ser convertido, os tokens expansíveis são expandidos.
Quando no final é reunido um número que não é positivo, como resultado da conversão (La)TeX não entregará nenhum token.
Assim, pode-se muito bem (ab?) usar \romannumeral
para desencadear muito trabalho de expansão e inversão de argumentos, desde que se garanta que no final \romannumeral
não encontrará um número positivo.
Aqui está uma variante deresposta da egrégiao que acontece com \romannumeral
e \exchange
em vez de \xdef
e \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}
Se você deseja agrupar o nome da macro que será definida em \csname
.. \endcsname
, ou seja, se desejar usar \csname savedexercises\endcsname
em vez de \savedexercises
, você pode aproveitar o fato de que (La)TeX expande tokens expansíveis enquanto coleta \csname
os nome de um token de sequência de controle e procurando a correspondência \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}
Esteja ciente de que com as abordagens apresentadas até agora você não pode usar \printexercises
exercícios em locais arbitrários. Você pode fazer com que os exercícios ocorram apenas em locais do documento que na fonte correspondem a locais atrás dos ambientes de exercício.
Talvez um ambiente que leia seu conteúdo em verbatim-catcode-régime para gravá-lo não expandido em .aux-file de uma forma onde a partir do .aux-file ele seja lido novamente em verbatim-catcode-régime também para definir uma macro onde \scantokens
será aplicado e, portanto, algum tipo de reimplementação do \label
- \ref
-mecanismo ou do \tableofcontents
-mecanismo para material textualizado pode tornar possível tornar os exercícios imprimíveis em todo o documento.
Implementar tal mecanismo pode ser um belo desafio. Mas antes de levar isso em consideração, são necessárias informações exatas sobre o uso pretendido e a "interface do usuário" desejada, ou seja, quais coisas adicionais você deseja especificar de que maneira, etc., ...
Responder4
Outra variante, usando filecontentsdef v1.4
, suporta verbatim
conteúdo (se necessário).
\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}