如何像 moodle.sty 那样解析分项列表

如何像 moodle.sty 那样解析分项列表

一个简单的moodle.sty数据库包含如下代码:

    \begin{multi}{Name of the question}
     Text of the question
     \item first answer
     \item secon answer
     \item* the starred is the correct answer
     ...
    \end{multi}

我需要从这样的数据库中提取文本、答案和正确答案。

multi我基本上成功地通过使用environ包重新定义环境并在包的帮助下进行解析来做到这一点listofitems,这要感谢那个问题

问题是问题和答案可能已经使用了等itemizeenumerate在这种情况下,每个都\item被解释为新答案的开始,整个过程就会崩溃。一种解决方法是将文本分组到括号中,但我需要使用现有数据库并且无法修改它们。

注意:显然,style 包moodle.sty完全满足了我的需求,因为它工作正常,但我无法从代码中理解它是如何工作的。(如果我可以复制并粘贴 moodle.sty 的一部分或去那里修改一些宏以满足我的需求,我会很高兴,但我对此的了解TeX并不那么深入)。

注意:软件包moodle.stygetitems.sty是由同一个人编写的。因此,既然moodle.sty运行良好,我猜它getitems比效果更好listofitems。有没有一种简单的方法可以替换上述答案中的listofitems使用?getitems

答案1

这真是糟糕的标记:您将无法在问题文本中使用列表。

无论如何,这是一个解析器。

\documentclass{article}
\usepackage{amsthm}
\usepackage{enumitem}

\newcounter{exercise}

\ExplSyntaxOn

\NewDocumentEnvironment{multi}{m +b}
 {
  \par\addvspace{\topsep}\setlength{\parindent}{0pt}
  \stepcounter{exercise}
  \textbf{Exercise~\theexercise}~--~#1\par\nobreak
  \moodle_multi:n { #2 }
  \par\addvspace{\topsep}
 }
 {}

\NewDocumentCommand{\showcorrect}{}
 {
  \bool_gset_true:N \g_moodle_multi_correct_bool
 }
\NewDocumentCommand{\hidecorrect}{}
 {
  \bool_gset_falsee:N \g_moodle_multi_correct_bool
 }

\bool_new:N \g_moodle_multi_correct_bool
\seq_new:N \l__moodle_multi_text_seq
\tl_new:N \l__moodle_multi_text_tl

\cs_new_protected:Nn \moodle_multi:n
 {
  \seq_set_split:Nnn \l__moodle_multi_text_seq { \item } { #1 }
  % the first item will contain the question text
  \seq_pop_left:NN \l__moodle_multi_text_seq \l__moodle_multi_text_tl
  \tl_use:N \l__moodle_multi_text_tl
  % now we rebuild the answers
  \begin{enumerate}[label=(\Alph*),nosep,labelsep=0.75em]
  \use:e
   {% add the first \item and put it also between the other items
    \__moodle_multi_item: \seq_use:Nn \l__moodle_multi_text_seq { \__moodle_multi_item: }
   }
  \end{enumerate}
 }

\cs_new_protected:Nn \__moodle_multi_item:
 {
  \item 
  \peek_charcode_remove:NT *
   {% there is an asterisk
    \bool_if:NT \g_moodle_multi_correct_bool { \__moodle_multi_correct: }
   }
 }

\cs_new_protected:Nn \__moodle_multi_correct:
 {
  \makebox[0pt][r]{\makebox[0pt][l]{$^{\scriptscriptstyle*}$}\hspace{\labelsep}}
  \ignorespaces
 }

\ExplSyntaxOff

\begin{document}

\begin{multi}{Name of the question}
  Text of the question
  \item first answer
  \item second answer
  \item* the starred is the correct answer
\end{multi}

\showcorrect

\begin{multi}{Name of the question}
  Text of the question
  \item first answer
  \item second answer
  \item* the starred is the correct answer
\end{multi}

\end{document}

在此处输入图片描述

正确答案的标记不占用水平空间,因此如果显示它,排版与没有它时相同。

我们可以在文本部分支持列表吗?可以,假设“答案”部分没有列表。

\documentclass{article}
\usepackage{amsthm}
\usepackage{enumitem}

\newcounter{exercise}

\ExplSyntaxOn

\NewDocumentEnvironment{multi}{m +b}
 {
  \par\addvspace{\topsep}\setlength{\parindent}{0pt}
  \stepcounter{exercise}
  \textbf{Exercise~\theexercise}~--~#1\par\nobreak
  \moodle_multi:n { #2 }
  \par\addvspace{\topsep}
 }
 {}

\NewDocumentCommand{\showcorrect}{}
 {
  \bool_gset_true:N \g_moodle_multi_correct_bool
 }
\NewDocumentCommand{\hidecorrect}{}
 {
  \bool_gset_falsee:N \g_moodle_multi_correct_bool
 }

\bool_new:N \g_moodle_multi_correct_bool
\seq_new:N \l__moodle_multi_text_seq
\tl_new:N \l__moodle_multi_text_tl
\tl_new:N \l__moodle_multi_moretext_tl
\tl_new:N \l__moodle_multi_answers_tl

\cs_new_protected:Nn \moodle_multi:n
 {
  \regex_split:nnN { \{(enumerate|itemize)\} } { #1 } \l__moodle_multi_text_seq
  \tl_set:Nx \l__moodle_multi_answers_tl { \seq_item:Nn \l__moodle_multi_text_seq { -1 } }
  \tl_set:Nn \l__moodle_multi_text_tl { #1 }
  \regex_replace_once:nnN { (.*)\u{l__moodle_multi_answers_tl} } { \1 } \l__moodle_multi_text_tl
  \seq_set_split:NnV \l__moodle_multi_text_seq { \item } \l__moodle_multi_answers_tl
  % the first item will contain the question text
  \seq_pop_left:NN \l__moodle_multi_text_seq \l__moodle_multi_moretext_tl
  \tl_use:N \l__moodle_multi_text_tl
  \tl_use:N \l__moodle_multi_moretext_tl
  % now we rebuild the answers
  \begin{enumerate}[label=(\Alph*),nosep,labelsep=0.75em]
  \use:e
   {% add the first \item and put it also between the other items
    \__moodle_multi_item: \seq_use:Nn \l__moodle_multi_text_seq { \__moodle_multi_item: }
   }
  \end{enumerate}
 }

\cs_new_protected:Nn \__moodle_multi_item:
 {
  \item 
  \peek_charcode_remove:NT *
   {% there is an asterisk
    \bool_if:NT \g_moodle_multi_correct_bool { \__moodle_multi_correct: }
   }
 }

\cs_new_protected:Nn \__moodle_multi_correct:
 {
  \makebox[0pt][r]{\makebox[0pt][l]{$^{\scriptscriptstyle*}$}\hspace{\labelsep}}
  \ignorespaces
 }

\ExplSyntaxOff

\begin{document}

\begin{multi}{Name of the question}
  Text of the question
  \begin{itemize}
  \item a
  \item b
  \end{itemize}
  More text
  \begin{enumerate}
  \item a
  \item b
  \end{enumerate}
  More text
  \item first answer
  \item second answer
  \item* the starred is the correct answer
\end{multi}

\showcorrect

\begin{multi}{Name of the question}
  Text of the question
  \item first answer
  \item second answer
  \item* the starred is the correct answer
\end{multi}

\end{document}

在此处输入图片描述

相关内容