
我正在嘗試為自己寫一個包,類似於練習包,這樣我就可以為我的學生準備問題集。我希望延遲問題和/或解決方案的輸出,直到我到達文件中的合適位置。我有一些東西可以用,但有點笨重。例如,這工作得很好:
\usepackage{environ}
\NewEnviron{testb}{\global\expandafter\let\csname bar\endcsname\BODY}
我使用是\csname
因為名稱是動態產生的。如果指令不是 ,則效果不太好\BODY
。例如,如果我這樣做\let\bar{\BODY}
,乳膠就會有動脈瘤(它只綁定\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 根本不會傳遞任何令牌。
因此,只要確保最終不會找到正數,就可以很好地(ab?)用於\romannumeral
觸發大量擴展工作和翻轉工作參數。\romannumeral
這是一個變體艾格格的回答它用\romannumeral
and\exchange
代替\xdef
and \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
在任意位置進行練習。您可以僅在文件中與練習環境後面的位置相對應的位置進行練習。
也許是一個環境,它確實在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}