l3:拆分和随机化标记列表

l3:拆分和随机化标记列表

我正在尝试掌握 LaTeX3 的来龙去脉。我想做以下事情:我定义了一个randomizechoices用于NewDoucmentEnvironment抓取内容的环境。然后解析此内容。解析时,我想将标记列表拆分为一个标记(序列),然后随机化该序列,然后重新构建标记列表。然后排版此标记列表。现在随机化标记列表不是直接可用的,但随机化序列是可用的。所以我需要将标记列表转换为(拆分)序列,将其随机化并重新构建标记列表(或以任何方式执行此操作)。MWE 如下所示:

\documentclass{exam}

\usepackage{xparse}

\ExplSyntaxOn

% for now
\NewDocumentCommand{\inaccessible}{}{X}

\NewDocumentEnvironment{randomizechoices}{ +!b }
  {
    \tl_set:Nn \l_my_tl {#1}
   
    \tl_replace_all:Nnn \l_my_tl {\CorrectChoice} {\choice \inaccessible}
    \tl_replace_all:Nnn \l_my_tl {\correctchoice} {\choice \inaccessible}

    % shuffle on \choice in token list
    
    % - or -
    
    % Convert to sequence on \choice, shuffle, rebuild
    
    % - or -
    
    % Convert to string, split on \choice to sequence, shuffle, rebuild
    
    %
  \begin{choices}
  \tl_use:N \l_my_tl
  \end{choices}
  }
  {}

\ExplSyntaxOff

\begin{document}

\begin{questions}

\question
Blah
\begin{randomizechoices}
\choice Hello
\choice World!
\CorrectChoice and
\choice everyone!
\end{randomizechoices}

\question
Blah
\begin{randomizechoices}
\choice Hello
\choice World!
\correctchoice and
\choice everyone!
\end{randomizechoices}

\end{questions}

\end{document}

答案1

下面通过使用序列来实现这一点。

\documentclass{exam}

\usepackage{xparse}

\ExplSyntaxOn

% for now
\NewDocumentCommand{\inaccessible}{}{X}

% initialize the used variables
\tl_new:N \l_my_body_tl
\seq_new:N \l_my_body_seq
\NewDocumentEnvironment{randomizechoices}{ +!b }
  {
    \tl_set:Nn \l_my_body_tl {#1}
    \tl_replace_all:Nnn \l_my_body_tl {\CorrectChoice} {\choice \inaccessible}
    \tl_replace_all:Nnn \l_my_body_tl {\correctchoice} {\choice \inaccessible}
    % set sequence split at \choice
    \seq_set_split:NnV \l_my_body_seq { \choice } \l_my_body_tl
    % remove empty elements
    \seq_remove_all:Nn \l_my_body_seq {}
    \seq_shuffle:N \l_my_body_seq
    % put back randomized sequence with \choice between the items
    \tl_set:Nx \l_my_body_tl
      {
        \exp_not:N \choice
        \seq_use:Nn \l_my_body_seq \choice
      }
  \begin{choices}
    \tl_use:N \l_my_body_tl
  \end{choices}
  }
  {}

\ExplSyntaxOff

\begin{document}

\begin{questions}

\question
Blah
\begin{randomizechoices}
\choice Hello
\choice World!
\CorrectChoice and
\choice everyone!
\end{randomizechoices}

\question
Blah
\begin{randomizechoices}
\choice Hello
\choice World!
\correctchoice and
\choice everyone!
\end{randomizechoices}

\end{questions}

\end{document}

在此处输入图片描述


这是基于@egreg 的精彩回答但改变了它的一些简单方面:

  • 我把标记改成了夸克
  • 我将该标记的测试更改为完全可扩展,这样用作输出的序列仅包含一次内容而不是三次(恕我直言,更干净的代码)
  • 增加放置标签的可能性(仅当你将种子设置expl3为固定值时才有意义)
\documentclass{exam}

\ExplSyntaxOn

\sys_gset_rand_seed:n { \fp_eval:n { round(1e6 * pi) } }

\NewDocumentEnvironment{randomizechoices}{ o +b }
  { \jodb_choices_randomize:nn {#1} {#2} }
  {}

% initialize the used variables
\tl_new:N \l_jodb_choices_body_tl
\seq_new:N \l_jodb_choices_body_in_seq
\seq_new:N \l_jodb_choices_body_out_seq

\quark_new:N \q__jodb_choices_marker

\cs_set_protected:Npn \jodb_choices_randomize:nn #1#2
  {
    \tl_set:Nn \l_jodb_choices_body_tl {#2}
    \tl_replace_all:Nnn \l_jodb_choices_body_tl
      {\CorrectChoice} {\choice \q__jodb_choices_marker}
    \tl_replace_all:Nnn \l_jodb_choices_body_tl
      {\correctchoice} {\choice \q__jodb_choices_marker}
    \seq_set_split:NnV \l_jodb_choices_body_in_seq
      { \choice } \l_jodb_choices_body_tl
    % first item is empty
    \seq_pop_left:NN \l_jodb_choices_body_in_seq \l_tmpa_tl
    % randomize
    \seq_shuffle:N \l_jodb_choices_body_in_seq
    % build another sequence
    \seq_set_map_x:NNn \l_jodb_choices_body_out_seq \l_jodb_choices_body_in_seq
      {
        \tl_if_head_eq_meaning:nNTF { ##1 } \q__jodb_choices_marker
          {
            \exp_not:n { \CorrectChoice }
            \IfValueT {#1} { \exp_not:n { \label{#1} } }
            \exp_not:o { \use_none:n ##1 }
          }
          { \exp_not:n { \choice ##1 } }
      }
    \begin{choices}
      \seq_use:Nn \l_jodb_choices_body_out_seq {  }
    \end{choices}
  }

\ExplSyntaxOff

\begin{document}

\printanswers

\begin{questions}

\question
Blah
\begin{randomizechoices}[ans:blah]
\choice Hello
\choice World!
\CorrectChoice and
\choice everyone!
\end{randomizechoices}

\question
Blah (but see also \ref{ans:blah})
\begin{randomizechoices}
\choice Hello
\choice World!
\correctchoice and
\choice everyone!
\end{randomizechoices}

\end{questions}

\end{document}

答案2

密钥是\seq_set_split:NnV,因此序列由以分隔的项目填充,\choice并且可以随机化。

\choice然后您可以通过重新插入或\CorrectChoice(如果项目中存在标记)来重建序列。

\documentclass{exam}

\ExplSyntaxOn

\NewDocumentEnvironment{randomizechoices}{ +b }
  {
    \jodb_choices_randomize:n { #1 }
  }
  {}

% initialize the used variables
\tl_new:N \l_jodb_choices_body_tl
\seq_new:N \l_jodb_choices_body_in_seq
\seq_new:N \l_jodb_choices_body_out_seq

\cs_new_protected:Nn \__jodb_choices_marker: { }

\cs_set_protected:Nn \jodb_choices_randomize:n
  {
    \tl_set:Nn \l_jodb_choices_body_tl {#1}
    \tl_replace_all:Nnn \l_jodb_choices_body_tl {\CorrectChoice} {\choice \__jodb_choices_marker:}
    \tl_replace_all:Nnn \l_jodb_choices_body_tl {\correctchoice} {\choice \__jodb_choices_marker:}
    \seq_set_split:NnV \l_jodb_choices_body_in_seq { \choice } \l_jodb_choices_body_tl
    % first item is empty
    \seq_pop_left:NN \l_jodb_choices_body_in_seq \l_tmpa_tl
    % randomize
    \seq_shuffle:N \l_jodb_choices_body_in_seq
    % build another sequence
    \seq_set_map_x:NNn \l_jodb_choices_body_out_seq \l_jodb_choices_body_in_seq
      {
        \tl_if_in:nnTF { ##1 } { \__jodb_choices_marker: }
          { \exp_not:n { \CorrectChoice ##1 } }
          { \exp_not:n { \choice ##1 } }
      }
    \begin{choices}
    \seq_use:Nn \l_jodb_choices_body_out_seq {  }
    \end{choices}
  }

\ExplSyntaxOff

\begin{document}

\printanswers

\begin{questions}

\question
Blah
\begin{randomizechoices}
\choice Hello
\choice World!
\CorrectChoice and
\choice everyone!
\end{randomizechoices}

\question
Blah
\begin{randomizechoices}
\choice Hello
\choice World!
\correctchoice and
\choice everyone!
\end{randomizechoices}

\end{questions}

\end{document}

抱歉,但为正确的选择添加标签是行不通的,因为每次运行 LaTeX 时引用通常都会发生变化。

在此处输入图片描述

相关内容