後で使用するためにテキストの断片を堅牢に保存する方法

後で使用するためにテキストの断片を堅牢に保存する方法

私は、演習パッケージに似たパッケージを自分で作成して、生徒用の問題セットを準備しようとしています。問題や解答の出力を、ドキュメント内の適切な場所に到達するまで遅らせたいと考えています。ある程度機能するものはありますが、少し扱いに​​くいです。たとえば、これはかなりうまく機能します。

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

\csname名前は動的に生成されるため、を使用します。 コマンドが 以外の場合、これはあまりうまく機能しません\BODY。 たとえば、 を使用すると\let\bar{\BODY}、latex には aneurysm があります ( \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例としてのみ使用しました。

ここに画像の説明を入力してください

2019-03-05 以降にリリースされた場合xparse:

\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、次の 2 つのマクロを使用するのが最適です。

\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を使用する場合は、(La)TeX が制御シーケンス トークンの名前を収集し、一致する を検索することによって、展開可能なトークンを展開するという事実を利用できます。\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}

ここに画像の説明を入力してください

これまで紹介したアプローチでは、\printexercises任意の場所で演習を行うことはできないことに注意してください。演習は、ソース内で演習環境の背後にある場所に対応するドキュメントの場所でのみ行うことができます。

おそらく、verbatim-catcode-régime でその内容を読み取り、それを .aux ファイルに展開せずに書き込む環境、そして .aux ファイルから verbatim-catcode-régime で読み戻して、適用されるマクロを定義する環境、そして、 verbatimized の内容に対する-メカニズムまたは - メカニズムの\scantokens何らかの再実装によって、ドキュメント全体にわたって演習を印刷可能にすることが可能になるかもしれません。\label\ref\tableofcontents

このようなメカニズムを実装するのは、なかなかのチャレンジかもしれません。しかし、それを考慮する前に、意図した使用法と望ましい「ユーザー インターフェイス」、つまり、どのような追加事項をどのような方法で指定できるようにしたいかなど、正確な情報が必要です。

答え4

別のバリエーションとして、 を使用するとfilecontentsdef v1.4verbatimコンテンツがサポートされます (必要な場合)。

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

得られた出力の例

関連情報