Как надежно хранить фрагменты текста для дальнейшего использования

Как надежно хранить фрагменты текста для дальнейшего использования

Я пытаюсь написать себе пакет, похожий на пакет упражнений, чтобы я мог подготовить наборы задач для своих студентов. Я хочу отложить вывод задач и/или решений до тех пор, пока не будет достигнуто подходящее место в документе. У меня есть что-то, что работает, но это немного неуклюже. Например, это работает довольно хорошо:

\usepackage{environ}
\NewEnviron{testb}{\global\expandafter\let\csname bar\endcsname\BODY}

Я использую, \csnameпотому что имена генерируются динамически. Это не работает так хорошо, если команда не \BODY. Например, если я использую \let\bar{\BODY}, у latex есть аневризма (он привязывается \barпросто к {).

Есть альтернативный способ сделать это:

\NewEnviron{testc}{\global\expandafter\edef\csname foo\endcsname{\BODY}}

Это вроде работает. Следующая вещь работает: \begin{testc}hi\end{testc}, но это приводит LaTeX к аневризме: \begin{testc}\bf hi\end{testc}. (Сообщение об ошибке \incomplete). Я пытался отладить его сам, но я безнадежно запутался в пакетах, которые я не понимаю. Если вы сделаете это с \tinyвместо , \bfвы получите совершенно другое сообщение об ошибке LaTeX:! TeX capacity exceeded, sorry [input stack size=5000].

Как мне приберечь на потом не просто \BODY, а некую сложную комбинацию \BODYи других вещей, сохраняя при этом то, что находится между началом и концом?

Редактировать: ок, несколько решений ниже

решение1

С \unexpandedним вы можете не беспокоиться ни о чем \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}

Я использовал это \newtheoremтолько для примера.

введите описание изображения здесь

С xparseвыпуском 2019-03-05 или позже:

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

решение2

Если вы хотите BODYсохраняться и добавлять данные динамически, вам, вероятно, лучше всего использовать два макроса:

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

Если вы хотите избежать использования, \BODYвы можете использоватьxparse

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

решение3

Для запуска расширения можно использовать \romannumeral:

Когда \romannumeral(La)TeX собирает вместе последовательность цифр, заканчивающуюся пробелом, в качестве числа, которое необходимо преобразовать, расширяемые токены расширяются.

Если в итоге получится число, которое не является положительным, то в результате преобразования (La)TeX вообще не выдаст ни одного токена.

Таким образом, можно с успехом (не?)использовать \romannumeralдля запуска большого количества работы по расширению и перестановке аргументов, пока гарантируется, что в итоге \romannumeralне будет найдено положительное число.

Вот вариантответ egregкоторый делает с \romannumeralи \exchangeвместо \xdefи \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}

введите описание изображения здесь

Если вы хотите заключить имя макроса, который должен быть определен, в \csname.. \endcsname, т. е. если вы хотите использовать \csname savedexercises\endcsnameвместо \savedexercises, вы можете воспользоваться тем фактом, что (La)TeX расширяет расширяемые токены, \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}

введите описание изображения здесь

Имейте в виду, что с подходами, представленными сейчас, вы не можете использовать \printexercisesдля того, чтобы упражнения происходили в произвольных местах. Вы можете иметь упражнения, происходящие только в тех местах документа, которые в источнике соответствуют местам за exercise-environments.

Возможно, среда, которая считывает свое содержимое в режиме verbatim-catcode-régime для нерасширенной записи его в .aux-файл таким образом, что из .aux-файла оно считывается обратно в режиме verbatim-catcode-régime также для определения макроса, к которому \scantokensбудет применено, и, таким образом, некоторая повторная реализация механизма \label- \refили механизма \tableofcontents- для дословно преобразованного материала могла бы сделать упражнения пригодными для печати по всему документу.

Реализация такого механизма может быть приятной задачей. Но прежде чем вообще принимать это во внимание, необходима точная информация о предполагаемом использовании и желаемом "пользовательском интерфейсе", т. е. какие дополнительные вещи вы хотите иметь возможность указывать, какими способами и т. д.

решение4

Другой вариант, с использованием filecontentsdef v1.4, Поддерживаетverbatim контент (при необходимости).

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

Пример полученного результата

Связанный контент