我有一些问题想解决,因为我正在尝试为我的考试任务建立一个宏。第一个问题是:有没有办法在变量定义中包含数字?假设我正在编写一个包含 10 个问题的测试考试,我想将\T1
问题 1 的答案分配给一个变量,\T2
将问题 2 的答案分配给另一个变量,等等。显而易见的事情,例如
\def\T1{answer 1}
\def\T2{answer 2}
或类似\newcommand
不起作用。有没有在变量定义中使用数字的正确方法?
第二个问题是:我有一个宏,它调用第二个宏,第二个宏在其上定义一个变量。当我尝试从主代码访问最内层宏中定义的变量的值时,系统会报错。那么有没有办法将变量名称和值保存在宏中,以便可以从外部访问它们?
谢谢,抱歉我的 TeX/LaTeX 知识太差 :(
答案1
有几种方法可以采用。这里有一个利用 TeX 的解决方案,\ifcase
对于这类事情非常有用:
\documentclass{article}
\usepackage[margin=1in]{geometry}
\newcounter{examquestion}
\newcommand{\question}{\stepcounter{examquestion}\noindent\textbf{Q\theexamquestion.)}\hspace*{1em}}
\newcommand{\answers}[1][\theexamquestion]{%
\ifcase#1\relax{This would be the answer to question 0: I presume there is no question 0}
\or{Answer to question 1}%
\or{Answer to question 2}%
\or{Answer to question 3}%
\or{Answer to question 4}%
\fi}%'
%% for purposes of this example only
\usepackage{lipsum}
\pagestyle{empty}
\begin{document}
\question \lipsum[1]
\par\hspace*{\fill}\textbf{Answer: \answers}
\vspace{0.25in}
\question \lipsum[2]
\par\hspace*{\fill}\textbf{Answer: \answers}
\vspace{0.25in}
\question \lipsum[3]
\par\hspace*{\fill}\textbf{Answer: \answers}
\vspace{0.25in}
Summary:
\begin{itemize}
\item \answers[1]
\item \answers[2]
\item \answers[3]
\end{itemize}
\end{document}
如果每个问题都有一个计数器,那么这种方法就很好用。我编写了命令\answers
,使其默认使用问题计数器的当前值examquestion
。但您可以覆盖它。您可能注意到,当提出答案时,我已经回答了每个问题。也许这不是您想要做的。我允许您覆盖此默认值。我在分项摘要中说明了这一点。
LaTeX3用更好的用户界面回答:
\documentclass{article}
\usepackage[margin=1in]{geometry}
\usepackage{xparse}
\ExplSyntaxOn
%% expl3::warnings and error messages
\msg_new:nnnn {examanswer}{answer_already_defined}{%
You're\ attempting\ to\ define\ an\ answer\ that\
already\ exists.\\
\\
\ \ \ \ Key\ "#1"\ already\ exists.
}{}
\msg_new:nnnn {examanswer}{answer_not_defined}{%
You're\ attempting\ to\ call\ an\ answer\ that\
has\ not\ been\ defined.\\
\\
\ \ \ \ Key\ "#1"\ does\ not\ exist.}{}
%% expl3 code to save and retrieve answers
\prop_new:N \g__answers_to_exam_problems_plist
\cs_new_protected:Npn \__setting_answers_cs:nn #1#2 {
\prop_if_in:NnTF \g__answers_to_exam_problems_plist {#1}
{
\msg_error:nnx{examanswer}{answer_already_defined}{#1}
}
{
\prop_gput:Nnn \g__answers_to_exam_problems_plist {#1} {#2}
}
}
\cs_new_protected:Npn \__getting_answers_cs:n #1 {
\prop_if_in:NnTF \g__answers_to_exam_problems_plist {#1}
{
\prop_get:Nn \g__answers_to_exam_problems_plist {#1}
}
{
\msg_error:nnx {examanswer}{answer_not_defined}{#1}
}
}
%% user interface to save and retrieve answers
\NewDocumentCommand{\saveanswer}{ m m }{
\__setting_answers_cs:nn {#1}{#2}
}
\NewDocumentCommand{\getanswer}{ m }{
\__getting_answers_cs:n {#1}
}
\ExplSyntaxOff
%% a bit of the old version: here purely for the sake of illustration
\newcounter{examquestion}
\newcommand{\question}{\stepcounter{examquestion}\noindent\textbf{Q\theexamquestion.)}\hspace*{1em}}
%% for purposes of this example only
\usepackage{lipsum}
\pagestyle{empty}
\begin{document}
\question \lipsum[1]
\saveanswer{q1ans}{This is the answer to question 1}
\vspace{0.25in}
\question \lipsum[2]
\saveanswer{q2ans}{Answer to question 2}
\vspace{0.25in}
\question \lipsum[3]
\saveanswer{Q:supplementary angles}{$m\angle{ABC}=30$}
\vspace{0.25in}
Summary:
\begin{itemize}
\item \getanswer{q1ans}
\item \getanswer{q2ans}
\item \getanswer{Q:supplementary angles}
\end{itemize}
\end{document}
我认为这种方法更好。它允许你独立于问题的实际编号来命名特定问题的答案:在这个例子中,我给出了最多的答案名称对应于提问的顺序。但是这段代码没有理由不让你写,
\setanswer{Q:supplementary angles}{$m\angle{ABC}=30$}
然后稍后调用它
\getanswer{Q:supplementary angles}
我更喜欢这种命名约定,因为它更具描述性:并且,如果您稍后重新排列问题,弄清楚神秘的含义\T1
就\getanswer{q1ans}
不会那么麻烦了。
我还添加了一些花哨的东西确保您不会覆盖以前定义的答案,并在调用未定义的答案时发出警告。
答案2
对于您的第一个问题:您可以定义一个宏 T1,但这对您没有帮助,因为您不能使用反斜杠语法调用它。请参见以下示例:
\documentclass{minimal}
\begin{document}
\expandafter\def\csname T1\endcsname{Test 1}
\expandafter\def\csname T2\endcsname{Test 2}
\csname T1\endcsname
\csname T2\endcsname
\T1
\end{document}
您可以改为定义一个宏\def\T#1{code}
,并使用 if-then 结构或类似结构来根据参数打印不同的问题。您可以使用\T1
, \T2
, ... ¸来调用它\T9
,但对于更高的值,您需要括号:\T{13}
。
对于第二个问题,一个最小的(不)工作示例会有所帮助。