这是故事“如何使用 moodle 数据库实现我的目的”的另一章。这个问题给出了一种非常有效的方法来从结构如下的练习数据库中检索信息
\begin{multi}{}
Text
\item first answer
\item* correct anser
...
\end{multi}
现在,作为“第 n 个答案”检索到的对象包含所有类型的间距,例如
\item
first answer
将存储\par
。
为了编辑目的,我想删除实际答案开始之前的所有“空白”空间。
Wipet 答案的示例不适合放在评论中。如果我设置
\documentclass{article}
\usepackage{getitems}
\begin{document}
\def\item{\futurelet\next \itemA}
\def\itemA{\ifx\next\par \expandafter\itemB \fi}
\long\def\itemB#1{\item}
\def\A{
A}
\def\B{%
B}
X\expandafter\item\A X
X\expandafter\item\B X
\end{document}
输出为
X
AX
XBX
因此\expandafter\item\A
不起作用(它之前包含换行符A
),而\expandafter\item\B
起作用(它之前不包含换行符B
)
答案1
在标记化过程中,控制\item
序列会占用其后的所有空间。因此,您只想删除标记为 的空白行\par
。如果您不要求可扩展宏,解决方案可能如下所示:
\def\item{\futurelet\next \itemA}
\def\itemA{\ifx\next\par \expandafter\itemB \fi}
\long\def\itemB#1{\item}
test:
aaa%
\item
bbb
\bye
另一种方法:假设我们定义了如下内容:
\def\TEXT{
\item
a b c
\item
d e f
g h i
}
我们希望创建一个新的宏,删除紧随其后的\TEXT
所有s 。这意味着在我们的示例中删除了first 之后的两个 s ,但保留了and之间的s。我们可以通过以下方式实现此目的\par
\item
\par
\item
\par
d e f
g h i
\rempars\TEXT
此宏改变了上面提到的主体\TEXT
。此宏可以定义为:
\long\def\addto#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}
\long\def\afterfi#1#2\fi{\fi#1}
\def\rempars #1{%
\let\orig=#1%
\def\tmp{}%
\expandafter\remparsA #1\item\par\endrempars
\expandafter\def\expandafter#1\expandafter{\tmp}%
\ifx#1\orig\else \afterfi{\rempars#1}\fi
}
\long\def\remparsA #1\item\par#2\endrempars{%
\if\relax\detokenize{#2}\relax \addto\tmp{#1}%
\else \addto\tmp{#1\item}\afterfi{\remparsA #2\endrempars}\fi
}
答案2
在上次我建议的代码中添加一些内容。
\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: }
\__moodle_multi_ignore:
}
}
\cs_new_protected:Nn \__moodle_multi_correct:
{
\makebox[0pt][r]{\makebox[0pt][l]{$^{\scriptscriptstyle*}$}\hspace{\labelsep}}
}
\cs_new_protected:Nn \__moodle_multi_ignore:
{% remove blank spaces and \par
\peek_regex_remove_once:nTF { [\s\c{par}]* } {} {}
}
\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}