我正在尝试创建一个新命令,该命令根据切换(带有特定的计数器 - 它基本上用于输出考试的问题和答案)输出第一个或第二个参数。
但是,如果答案或问题中有空行,则命令失败并出现错误:
Runaway argument? {
Paragraph ended before \QR was complete.
Too many }'s. }
MWE 是:
\documentclass{article}
\usepackage{xparse}
\usepackage{enumitem}
\usepackage{etoolbox}
\usepackage{listings}
% Make toggle for teacher and student version of file
\newtoggle{corrige}
\togglefalse{corrige}
\newcommand{\cswitch}[2]{
\iftoggle{corrige}{%
#1%
}{%
#2%
}%
}
% Make a fancy QR command
\newcounter{qrIndex} % compteur pour les questions
\newcounter{qrIndexSaved}
\newcommand{\save}{\setcounter{qrIndexSaved}{\theqrIndex}}
\newcommand{\retrieve}{\setcounter{qrIndex}{\theqrIndexSaved}}
\newcommand{\resetQ}{\setcounter{qrIndex}{1}}
\NewDocumentCommand{\QR}{mm}{%
\begin{enumerate}[start=\theqrIndex]
\stepcounter{qrIndex}
\cswitch{\item #2}{\item #1}%
\end{enumerate}%
}
\begin{document}
\toggletrue{corrige}
Test switch corrige~: \cswitch{corrige}{enonce}
\bigbreak
Test QR~:
\resetQ
\QR{Q1}{A1}
\QR{
Q2
}{
This has no empty line in either the question or answer.
\smallbreak
It works well.
}
\QR{
Q3
}{
This \textbf{has} an empty line.
You'd think it works.
But error:
\begin{verbatim}
Runaway argument? {
Paragraph ended before \QR was complete.
Too many }'s. }
\end{verbatim}
It only shows the last part of answer, skipping anything before, and messes
up the enumerate etc, even without the \texttt{toggletrue\{corrige\}}!
}
\end{document}
我的猜测是它来自命令和/或中的\iftoggle
第二个参数的扩展,但我在网上没有找到类似的案例。xparse
NewDocumentCommand
感谢您的帮助!
答案1
TeX 区分长宏(由 声明\long\def
),其参数接受空行,以及短宏(由 声明\def
)。由于历史原因,LaTeX 宏默认\newcommand
创建宏,而您需要带星号的形式来创建短宏。另一方面,来自 的参数默认也是短的,您需要使用说明符来允许宏参数中有空行。\long
\newcommand*
m
xparse
+m
还要注意,计数器值应通过\value{counter}
而不是传递\thecounter
。在这种情况下你很幸运,因为\thecounter
默认为阿拉伯语表示,但你不应该依赖它。
最后但同样重要的一点是,verbatim
环境从未作为其他宏的参数。
现在轮到你可以修复这些问题并使其正常工作:
\documentclass{article}
\usepackage{enumitem}
\usepackage{etoolbox}
% Make toggle for teacher and student version of file
\newtoggle{corrige}
\togglefalse{corrige}
\newcommand{\cswitch}[2]{%
\iftoggle{corrige}{%
#1%
}{%
#2%
}%
}
% Make a fancy QR command
\newcounter{qrIndex} % compteur pour les questions
\newcounter{qrIndexSaved}
\newcommand{\save}{\setcounter{qrIndexSaved}{\value{qrIndex}}}
\newcommand{\retrieve}{\setcounter{qrIndex}{\value{qrIndexSaved}}}
\newcommand{\resetQ}{\setcounter{qrIndex}{1}}
\NewDocumentCommand{\QR}{+m+m}{% or simply \newcommand{\QR}[2]
\begin{enumerate}[start=\value{qrIndex}]
\stepcounter{qrIndex}
\cswitch{\item #2}{\item #1}%
\end{enumerate}%
}
\begin{document}
\toggletrue{corrige}
Test switch corrige~: \cswitch{corrige}{enonce}
\bigbreak
Test QR~:
\resetQ
\QR{Q1}{A1}
\QR{
Q2
}{
This has no empty line in either the question or answer.
\smallbreak
It works well.
}
\QR{
Q3
}{
This \textbf{has} an empty line, and it works.
}
\end{document}
但是,既然你正在使用enumitem
,为什么不利用它的功能呢?你可以定义一个自动恢复的新列表:
\documentclass{article}
\usepackage{enumitem}
\usepackage{etoolbox}
% Make toggle for teacher and student version of file
\newtoggle{corrige}
\togglefalse{corrige}
\newcommand{\cswitch}[2]{\iftoggle{corrige}{#1}{#2}}
% Make a fancy QR command
\newlist{mylist}{enumerate}{1}
\setlist[mylist]{resume,label=\arabic{mylisti}.}
\newcommand{\resetQ}{\restartlist{mylist}}
\NewDocumentCommand{\QR}{+m+m}{%
\begin{mylist}
\item\cswitch{#2}{#1}%
\end{mylist}%
}
\begin{document}
\toggletrue{corrige}
\QR{Q1}{A1}
\QR{Q2}{A2}
\QR{Q3}{A3}
\togglefalse{corrige}
\resetQ
\QR{QQ1}{AA1}
\QR{QQ2}{AA2}
\QR{QQ3}{AA3}
\end{document}