收集环境内容(包含逐字内容)

收集环境内容(包含逐字内容)

编辑:附加和具体的信息。

有一些有用的背景信息,希望能够清楚地说明我正在做什么,以及发生这种情况的相关环境。我将在 ----- 行后添加特定于问题的信息。

这是一个名为 Ximera 的教育材料开源项目。我正在编辑代码以供另一所大学使用,并将这些更改推送到原始项目。您可以找到 cls 文件的所有已编辑代码这里(所有附带代码也位于该 github repo 中)。

该项目使用静态编译顺序,这在更具创造性的解决方案方面为我提供了一些有限的选择(例如,我会使用 sage 来处理一些所需内容,但编译器是静态的,不会编译 sage)。编译器不是针对 tex 代码定制的,尽管它确实对 mathjax 和其他一些我不确定其工作原理的部分做了一些神奇的事情。

作为一个开源项目,其中很多代码都是拼凑起来的。我一直在精简、清理和注释与项目这一部分相关的尽可能多的代码,因此它应该比人们预期的更具可读性。


现在,我实际的问题是如何结合“python”代码环境实现 shuffle 环境功能。您可以在上面的链接中搜索 shuffle 环境代码(大约 860 行),以获取 shuffle 的完整代码,该代码(相对)独立,您可以找到 python/code 环境(大约 750 行)。

紧接着“shuffle”环境本身的是问题环境类型的所有代码(有几种,但唯一的区别是显示的名称,这从实现代码中应该可以清楚)。

我的想法是使用 Environ 命令收集任何问题内容,​​将其分配给基于 shuffle 和问题编号创建的命令。然后,当 shuffle 环境关闭时,我们会遍历问题以随机顺序显示它们。pgfplots 包提供的随机数,以及我编写的自定义命令,用于生成和排列数字向量,保存在命令和计数器中。

由于代码是在链接中编写的,因此 shuffle 在各种问题环境中都能很好地工作。但是,environ 包显然在逐字环境中不能很好地工作。而且由于代码/python 环境是逐字环境,如果我们在问题中包含其中一个,一切都会崩溃。因此,这里有一个使用上面链接中的项目代码的完整工作/非工作示例。

%\documentclass[handout]{ximera}
\documentclass[]{ximera}

\begin{document}

\begin{shuffle}[5]
\begin{exploration}% This is a basic one example that works.

Compute the following derivative:
%\expandafter\input{\file@loc Derivatives/2311-Compute-Derivative-0001.HELP.tex}
\[
\dfrac{d}{dx}\left({x^{2} - 8 \, x + 16}\right)=\answer{2 \, x - 8}
\]

\end{exploration}

\begin{problem}% This example fails due to python
This is the second problem! The answer is $\answer{6}$
\begin{hint}
test
\end{hint}

%\begin{python}% python throws a fancyvrb error
%Test
%\end{python}
\end{problem}


\begin{question}% Display mode works as an environment
This is the third problem! I need to include some other code, so here;
\[
3x + 1 = 5
\]
What is $x$? $\answer{\frac{4}{3}}$
\end{question}


\begin{exercise}
This is the fourth problem!
\begin{theorem}% Theorem environment works
The Intermediate Value Theorem is never done right by students. What is the point of this theorem?
\end{theorem}
$\answer{Nothing}$

\begin{exploration}% This doesn't appear, probably because of the approach
This just doesn't appear
\end{exploration}

\end{exercise}


\begin{problem}% This example fails.
This is the fifth problem! Lets try some nested content

%Verbatim env throw errors
%\begin{verbatim}
%Here is a hint!
%\end{verbatim}

\end{problem}


\end{shuffle}



\end{document}

上面列举了一些可以工作和不工作的例子。verbatim 和 python 环境直接失败(我认为是出于同样的原因,因为 python 是 fancyvrb 创建的 verbatim 环境)。environ 包对很多其他事情都很有用,所以如果可能的话,我希望修复 verbatim 方面的问题。

顺便说一句,我还不会做嵌套问题。我很确定那只是因为 shuffle 的运行方式,而这目前在我的列表中并不是太重要。如果能使嵌套工作就好了,但不是必需的。

答案1

您可以轻松实现一个环境,逐字读取其主体,然后在宏定义中将其包装到其中\scantokens

执行宏时,\scantokens将会被执行,并且事物将不再在 verbatim-catcode-régime 下而是在正常的 catcode-régime 下重新标记,这意味着这次像命令 \verb或环境这样的环境verbatim和其他像 verbatim 的环境(例如代码列表)将得到执行。

以下示例提供了一个环境Problem

如果您在该环境的可选参数中提供了一个名称,那么您可以通过以下方式重述环境的内容 \RestateProblem{<Name>}

Problem-environment 包含\verbverbatim-environments 之类的内容时,它也有效。

Problem-环境不能嵌套,因为这些环境的整个主体被视为由短语分隔的宏参数\end{Problem}(也以逐字方式标记)。

还可以创建类似于\label..的机制\ref,以便将内容以逐字逐句的方式写入 .aux 文件,提供文本中前向和后向引用的功能。

如果您将这样的重述与宏\section 或计数器步进的环境结合使用\theorem,您可能会得到不必要的结果,因为每次重述都会导致相应的计数器步进......

如果是前向引用,您需要确保在前向引用发生时所有计数器、控制序列都已定义......

如果是向后引用,您需要确保所有计数器、控制序列都不会以在引用时引起麻烦的方式重新定义……

请注意,我尚未详细阐述这一点,因为这种事情需要根据实际/特定需求进行大量繁琐且耗时的调整。

在根据提问者的实际需求进行调整的过程中,需要花费大量的时间和精力去完全重写某些内容,这种风险很高。

因此我建议您尽可能详细地说明您的需求。

别把你的问题当成是表现谦虚的问题。

相反,以有效的方式提供所有有助于提供帮助的信息/请求/要求。

在此处输入图片描述

\documentclass{article}
\makeatletter
%%
%%  Snippet written by Ulrich Diez on June 8, 2017
%%  License: LPPL.
%%
%%----------------------------------------------------------------------
%% Check whether argument is empty:
%%......................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is empty>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
%%
%% (\romannumeral expansion was introduced in order to overcome the
%% concerns and worries about improperly balanced \if..\else..\fi constructs.)
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@exchange[2]{#2#1}%
\newcommand\UD@CheckWhetherNull[1]{%
  \romannumeral0\expandafter\UD@secondoftwo\string{\expandafter
  \UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
  \UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}%
  \UD@secondoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@firstoftwo}%
}%
%%----------------------------------------------------------------------
%% Put a control sequence token in place instead of the string denoting
%% its name:
%%......................................................................
%%  \Name<emptiness or tokens other than braces>{<Name of Control Sequence>}
%%
%% yields:
%%
%%  <emptiness or tokens other than braces>\Controlsequence
%%
%% E.g.,
%%
%%   \Name foo{bar} -> foo\bar
%%   \Name{bar} -> \bar
%%   \Name\newcommand*{wEirdName}[1]{Arg 1: (#1)}
%%       -> \newcommand*\wEirdName[1]{Arg 1: (#1)}
%%
\newcommand\Name{}\long\def\Name#1#{\romannumeral\UD@name{#1}}%
\newcommand\UD@name[2]{%
  \expandafter\UD@exchange\expandafter{\csname#2\endcsname}{0 #1}%
}%
%%----------------------------------------------------------------------
%% Implement generic stuff for reading arguments "verbatim":
%%......................................................................
%%
% Syntax of \UDcollectOneVerbArg
%
%   \UDcollectOneVerbArg{<^^M-replacement>}{<mandatory>}<delimiter of verbatim arg><verbatim arg><delimiter of verbatim arg>
%   yields:
%   <mandatory>{<verbatim arg>}
%
% with each character ^^M (usually=\endline-char) in <verbatim arg>
% replaced by token-sequence <^^M-replacement>.
%
% If reading <^^M-replacement> and <mandatory> from input is necessary,
% they will be read under unchanged catcode regime.
%
% The <verbatim arg> is also mandatory.
% It will be read under verbatim-catcode-conditions.
% There must be a leading character in front of it.
%
% Empty-lines will not be ignored.
%
% <delimiter of verbatim arg> will be read under verbatim-catcode-conditions
% if present.
%
%
\begingroup
\catcode`\^^M=12 %
\UD@firstoftwo{%
  \endgroup%
  \newcommand\UDEndlreplace[2]{\romannumeral0\@UDEndlreplace{#2}#1^^M\relax{}}%
  \newcommand*\@UDEndlreplace{}%
  \long\def\@UDEndlreplace#1#2^^M#3\relax#4#5{%
    \UD@CheckWhetherNull{#3}%
    { #5{#4#2}}{\@UDEndlreplace{#1}#3\relax{#4#2#1}{#5}}%
  }%
}{}%
\newcommand\UDcollectOneVerbArg{\@UDOneVerbArg{\@UDcollectOneVerbArg}}%
\newcommand\@UDOneVerbArg[3]{%
  \@bsphack
  \begingroup
  \let\do\@makeother\dospecials
  \catcode`\ =10 %
  \@@UDOneVerbArg{#1}{#2}{#3}%
}%
\newcommand\@@UDOneVerbArg[4]{%
  \do\ %
  \catcode`\^^M=12 %
  \long\def\@tempb##1#4{%
    \def\@tempb{##1}%
    \expandafter\UDEndlreplace\expandafter{\@tempb}{#2}{\def\@tempb}%
    \expandafter#1\expandafter{\@tempb}{#3}%
  }%
  \@tempb
}%
\newcommand\@UDcollectOneVerbArg[2]{%
  \endgroup
  \@esphack
  #2{#1}%
}%
% Implementation of generic stuff for reading arguments "verbatim" done.
%%
%%
%%----------------------------------------------------------------------
%% Implement generic stuff for defining Problem-like environments:
%%......................................................................
% #1 - Name of environment
\newcommand\DefineVerbReadBodyEnv{%
  \UDcollectOneVerbArg{^^J}{\InnerDefineVerbReadBodyEnv}%
}%
% ##1 - \end{
% ##2 - }
% ####1 - <Name of environment>
\newcommand\InnerDefineVerbReadBodyEnv[1]{%
  \renewcommand\InnerDefineVerbReadBodyEnv[2]{%
    \renewcommand\InnerDefineVerbReadBodyEnv[1]{%
      \Name\newcommand{Restate####1}[1]{%
         \Name{####1@########1}%
      }%
      \Name\newcommand{process####1}[2]{%
        \UD@CheckWhetherNull{########1}{}{%
          \Name\newcommand{####1@########1}{%
            \scantokens{\csname UD@firstoftwo\endcsname{}{}########2\begingroup\catcode`\X=14 X}\endgroup
          }%
          \Name\Name\global\let{####1@########1}={####1@########1}%
        }%
        \scantokens{\csname UD@firstoftwo\endcsname{}{}########2\begingroup\catcode`\X=14 X}\endgroup
        \end{####1}%
      }%
      \newenvironment{####1}[1][]{%
        \UDcollectOneVerbArg{^^J}{\Name{process####1}{########1}}{##1####1##2}%
      }{%
      }%
    }%
  }%
  \UDcollectOneVerbArg{^^J}{\InnerDefineVerbReadBodyEnv{#1}}%
}%
\UDcollectOneVerbArg{^^J}{\InnerDefineVerbReadBodyEnv}|\end{||}|%
%%
%% Generic stuff for defining Problem-like environments done.
%%
\makeatother

\DefineVerbReadBodyEnv|Problem|

\begin{document}

\fbox{Problem stated the first time:}

\begin{Problem}[First Problem]%
This is normal text.
\verb|This is from the verb command.|
\verb*|This is from the verb* command.|    
This is normal text.
\begin{verbatim}
This is from the verbatim environment:
&%{}§_"`´~
\end{verbatim}
\end{Problem}

\fbox{Problem restated:}

\RestateProblem{First Problem}

\fbox{Problem restated once more:}

\RestateProblem{First Problem}

\end{document}

答案2

我对 .cls 文件中内容的理解是否正确?:

您希望拥有一个环境shuffle,其中特定的其他环境可用于编写/保存文本部分。在处理环境结束时,保存的文本部分应以随机顺序放置在输出文件/.pdf 文件中shuffle

如果我理解正确的话,会出现几个问题:

  1. 如何处理环境中shuffle没有放置在这些特定的其他环境中的事物?

    [我看到两种可能性:

    1. 正常处理这些事情。
    2. tikzpicture尝试完全忽略这些事情。它们可能可以以与从包中绘制图像的环境相同的方式处理蒂克兹  处理事物,例如使用空字体等,确保不产生可见输出。或者像xcomment.sty其中可以指定要处理的环境,同时忽略任何其他代码。]
  2. 如何处理嵌套这种特定的其他环境的情况?

  3. 如何处理此类特定其他环境的主体包含不平衡内容的情况,例如,不平衡的左括号、不平衡的右括号、不平衡的、不平衡的\if..\else..\fi\begingroup不平衡的、\endgroup不平衡的、\bgroup不平衡的\egroup、不平衡的\begin{whatsoever environment}、不平衡的\end{whatsoever environment}、不平衡的\csname、不平衡的\endcsname,...

  4. 如果文本的各部分应按随机顺序排列,则意味着产生随机数。(据我所知,该包前列腺素附带一个随机数生成器。)

    我看到你实现了一些变体Fisher Yates Shuffle 算法这意味着需要一组随机数,其基数比要随机打乱的文本部分的数量小 1。

    [相反——我提到这一点更像是一个没有实际意义的问题——你也可以尝试应用,例如,莱默法典(<https://en.wikipedia.org/wiki/Lehmer_code> ) 用于双射映射到 0 到 (n! - 1)一组的所有排列n不同元素可双射映射到 0 到 (n - 1):随机选择一个排列不同元素 (0< ≤ n) 从n这样的元素,选择一个随机数R  在 0 至 ( 范围内n!/((n -  ) ) - 1),设数字年代  是R·((n -  ) ),应用Lehmer解码算法年代  为了获得n元素莱默法典映射到年代 ,并从该排列中仅保留第一个/前导元素。
    这只需要一个随机数,但需要进行大量的算术运算,例如计算下降n, 和莱默-解码。
    算术可能可以用以下方法完成Heiko Oberdiek 的包裹bigintcalc,但我想这样的事情在 LaTeX 编译时可能会非常耗时。]

    看来,无论如何你都需要一组随机数。

    关于 LaTeX 的关键点是:

    通常需要多次编译 LaTeX 文档的源代码,直到\label-\ref参考文献或参考书目和许多其他内容正确匹配。如果在每次 LaTeX 编译中重新创建随机变量的值,您可能会得到一个永无止境的编译故事,因为在每次编译中,随机变量的值以及与这些随机变量相关的文本(!)可能会发生变化,而需要连续的 LaTeX 编译才能使参考文献正确匹配,而在这些连续的编译过程中,随机变量的值以及与这些随机变量相关的文本可能会再次发生变化,再次需要连续的 LaTeX 编译才能使参考文献正确匹配,再次导致改变随机变量的值,再次导致改变与这些随机变量相关的文本......

    因此,您可能需要某种机制/系统来保存在第一次 LaTeX 编译期间创建的随机变量的值,以便在连续的 LaTeX 编译期间使用。可能是从\label- -\ref机制派生出来的,这样您就可以让 (La)TeX 尝试从标签中获取随机变量的值,如果失败,则通过随机生成器创建它,并在任何情况下将其保存在标签中以供连续的 LaTeX 编译使用...(- \label-\ref机制提供了警告/通知用户在发生任何变化时需要重新运行 LaTeX 的功能。)

    有了这样的机制/系统,您需要为这些标签制定命名约定,以便自动为标签创建唯一/明确的名称。可能基于对环境的计数shuffle以及对可能在环境中出现的上述特定环境的计数shuffle...

相关内容