Como armazenar de forma robusta pedaços de texto para uso posterior

Como armazenar de forma robusta pedaços de texto para uso posterior

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 \csnameporque 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 \barapenas 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 \tinyem vez de, \bfreceberá 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 \BODYe 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 \unexpandedvocê 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 \newtheoremapenas para exemplo.

insira a descrição da imagem aqui

Com xparselanç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 BODYser 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, \BODYvocê 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 \romannumeralpara desencadear muito trabalho de expansão e inversão de argumentos, desde que se garanta que no final \romannumeralnão encontrará um número positivo.

Aqui está uma variante deresposta da egrégiao que acontece com \romannumerale \exchangeem vez de \xdefe \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}

insira a descrição da imagem aqui

Se você deseja agrupar o nome da macro que será definida em \csname.. \endcsname, ou seja, se desejar usar \csname savedexercises\endcsnameem vez de \savedexercises, você pode aproveitar o fato de que (La)TeX expande tokens expansíveis enquanto coleta \csnameos 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}

insira a descrição da imagem aqui

Esteja ciente de que com as abordagens apresentadas até agora você não pode usar \printexercisesexercí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 \scantokensserá 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 verbatimconteú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}

Exemplo da saída obtida

informação relacionada