其他方法

其他方法

我想了解是什么导致下面的操作不起作用,以及如何修复它以便在每次调用命令时获得所需的输出\myQFormat

\documentclass[addpoints]{exam}

\usepackage{xparse}
\usepackage[xparse]{tcolorbox}

\renewcommand{\questionshook}{%
    \setlength{\leftmargin}{0pt}%
    \setlength{\labelwidth}{-\labelsep}%
}

\NewTColorBox{MarksTCBox} { O{} }{
    left skip= 0pt,
    right skip=0pt,
    left=2pt,
    right=2pt,
    capture=hbox,
    halign=center,
    valign=center,
    boxrule=0pt,
    arc=0pt,
    top=2pt,
    bottom=2pt,
    boxsep=0pt,
    nobeforeafter,
    box align = base,
    baseline=4pt,
    #1
}

\ExplSyntaxOn

\keys_define:nn { Qoptions }
{
    label       .tl_set:N  = \l__Qoptions_label_tl,
    label       .initial:n = Question,
    sublabel    .tl_set:N  = \l__Qoptions_sublabel_tl,
}

\cs_new:Npn \Question_header:n #1
{
    \qformat{
        \textbf{
            \underline{
                \large \tl_if_blank:nTF {\l__Qoptions_label_tl} { Question } { \l__Qoptions_label_tl }~
                (\thequestion)\ \IfValueT{\l__Qoptions_sublabel_tl}{[\l__Qoptions_sublabel_tl]\ }
                \begin{MarksTCBox}
                    \scan_stop: [\totalpoints\ Marks]
                \end{MarksTCBox}
            }
        }
    }
}

\NewDocumentCommand { \myQFormat } { O{} }
{
    \group_begin:
    \keys_set:nn { Qoptions } { #1 }
    \Question_header:n { #1 }
    \group_end:
}

\ExplSyntaxOff

\begin{document}
    \begin{questions}

        \myQFormat
        \question[15]\hspace*{0pt}\vspace*{\baselineskip}
        The output should be ``Question 1 [15 Marks]''

        \myQFormat[label = Part]
        \question[10]\hspace*{0pt}\vspace*{\baselineskip}
        The output should be ``Part 2 [10 Marks]''

        \myQFormat[label=Part, sublabel=Subtitle]
        \question[5]\hspace*{0pt}\vspace*{\baselineskip}
        The output should be ``Part 3 [Subtitle] [5 Marks]''

        \myQFormat[sublabel=Subtitle]
        \question[10]\hspace*{0pt}\vspace*{\baselineskip}
        The output should be ``Question 4 [Subtitle] [10 Marks]''

    \end{questions}
\end{document}

答案1

主要问题有:

  • \tl_if_blank:nTF需要一个带括号的“普通参数”(n类型),直接包含要测试的标记,例如\tl_if_blank:nTF { abc~def } { true } { false },如果我们在宏定义中,并且参数#1是标记列表,则\tl_if_blank:nTF {#1} { true } { false }。但你在这里想要测试的是标记列表变量的内容(值)。为此,你需要\tl_if_blank:VTFV原因价值传递给基本形式的第一个参数\tl_if_blank:nTF)。 例如:

    \tl_if_blank:VTF \l__my_var_tl { true } { false }
    
  • 当你的\myQFormat已完全执行时,它\group_end:已将两个标记列表变量\l__Qoptions_label_tl和恢复\l__Qoptions_sublabel_tl为组开始之前的值,即此处为空。因此,当\question使用这些变量作为问题格式的一部分时,它们都是空的。

对于第二点,以下代码\keys_set:nn在的参数中调用。这允许您在格式定义中\qformat使用名称\l__Qoptions_label_tl和。我将在下面展示另一种可能的方法。\l__Qoptions_sublabel_tl

正如 egreg 所指出的,\tl_if_blank:...标签的测试实际上并不是必需的,因为的初始值\l__Qoptions_label_tl是用设置的label .initial:n = { Question }(可以省略括号,因为中没有逗号Question)。此测试唯一有用的情况是,当您希望在使用选项label=或 even时获得“Question”作为标签时label={ }(实际上,“blank”在此上下文中表示“空或仅空格”,因此,如果您传递仅包含空格标记的参数,\tl_if_blank:nTF将执行“true”分支)。

\documentclass[addpoints]{exam}
\usepackage{xparse}
\usepackage[xparse]{tcolorbox}

\renewcommand{\questionshook}{%
  \setlength{\leftmargin}{0pt}%
  \setlength{\labelwidth}{-\labelsep}%
}

\NewTColorBox{MarksTCBox} { O{} }{
    left skip= 0pt,
    right skip=0pt,
    left=2pt,
    right=2pt,
    capture=hbox,
    halign=center,
    valign=center,
    boxrule=0pt,
    arc=0pt,
    top=2pt,
    bottom=2pt,
    boxsep=0pt,
    nobeforeafter,
    box align = base,
    baseline=4pt,
    #1,
}

\ExplSyntaxOn

\keys_define:nn { Qoptions }
  {
    label       .tl_set:N  = \l__Qoptions_label_tl,
    label       .initial:n = { Question },
    sublabel    .tl_set:N  = \l__Qoptions_sublabel_tl,
  }

\cs_new_protected:Npn \Qoptions_question_header:n #1
  {
    \qformat
      {
        % \question appears to create a group, so the options are duly cleared
        % when the question title has been typeset.
        \keys_set:nn { Qoptions } {#1}
        \textbf
          {
            \underline
              {
                \large
                % Possible but not really needed (see above):
                % \tl_if_blank:VTF \l__Qoptions_label_tl { Question }
                %   { \l__Qoptions_label_tl }
                \tl_use:N \l__Qoptions_label_tl
                \nobreakspace \thequestion \
                \tl_if_blank:VF \l__Qoptions_sublabel_tl
                  { [ \l__Qoptions_sublabel_tl ] \ }
                \begin{MarksTCBox}
                    \scan_stop: [\totalpoints\ Marks]
                \end{MarksTCBox}
              }
          }
          \hfill % Otherwise, you'll have an Underfull \hbox for each question.
      }
  }

\NewDocumentCommand { \myQFormat } { O{} }
  {
    \Qoptions_question_header:n {#1}
  }

\ExplSyntaxOff

\begin{document}
  \begin{questions}

    \myQFormat
    \question[15]\hspace*{0pt}\vspace*{\baselineskip}
    The output should be ``Question 1 [15 Marks]''

    \myQFormat[label = Part]
    \question[10]\hspace*{0pt}\vspace*{\baselineskip}
    The output should be ``Part 2 [10 Marks]''

    \myQFormat[label=Part, sublabel=Subtitle]
    \question[5]\hspace*{0pt}\vspace*{\baselineskip}
    The output should be ``Part 3 [Subtitle] [5 Marks]''

    \myQFormat[sublabel=Subtitle]
    \question[10]\hspace*{0pt}\vspace*{\baselineskip}
    The output should be ``Question 4 [Subtitle] [10 Marks]''

  \end{questions}
\end{document}

在此处输入图片描述

其他方法

避免因过早恢复\l__Qoptions_label_tl和的值(在使用它们之前)而导致问题的另一种方法如下。您可以通过\l__Qoptions_sublabel_tl\questionof\l__Qoptions_label_tl\l__Qoptions_sublabel_tlto\Qoptions_question_header:n使用V参数类型。由于您有两个“正常参数”要传递,因此该函数现在必须命名\Qoptions_question_header:nn并接受两个参数#1#2(标签和子标签)。然后您可以使用\cs_generate_variant:Nn \Qoptions_question_header:nn { VV }创建所需的函数变体(即\Qoptions_question_header:VV),并调用\Qoptions_question_header:VV \l__Qoptions_label_tl \l__Qoptions_sublabel_tl\myQFormat传递\l__Qoptions_label_tl\l__Qoptions_sublabel_tl\Qoptions_question_header:nn

\documentclass[addpoints]{exam}
\usepackage{xparse}
\usepackage[xparse]{tcolorbox}

\renewcommand{\questionshook}{%
  \setlength{\leftmargin}{0pt}%
  \setlength{\labelwidth}{-\labelsep}%
}

\NewTColorBox{MarksTCBox} { O{} }{
    left skip= 0pt,
    right skip=0pt,
    left=2pt,
    right=2pt,
    capture=hbox,
    halign=center,
    valign=center,
    boxrule=0pt,
    arc=0pt,
    top=2pt,
    bottom=2pt,
    boxsep=0pt,
    nobeforeafter,
    box align = base,
    baseline=4pt,
    #1,
}

\ExplSyntaxOn

\keys_define:nn { Qoptions }
  {
    label       .tl_set:N  = \l__Qoptions_label_tl,
    label       .initial:n = { Question },
    sublabel    .tl_set:N  = \l__Qoptions_sublabel_tl,
  }

\cs_new_protected:Npn \Qoptions_question_header:nn #1#2
  {
    \qformat
      {
        \textbf
          {
            \underline
              {
                \large
                % Possible but not really needed (see above):
                % \tl_if_blank:nTF {#1} { Question } {#1}
                #1 \nobreakspace \thequestion \
                \tl_if_blank:nF {#2} { [ #2 ] \ }
                \begin{MarksTCBox}
                    \scan_stop: [\totalpoints\ Marks]
                \end{MarksTCBox}
              }
          }
          \hfill % Otherwise, you'll have an Underfull \hbox for each question.
      }
  }

\cs_generate_variant:Nn \Qoptions_question_header:nn { VV }

\NewDocumentCommand { \myQFormat } { O{} }
  {
    \group_begin:
    \keys_set:nn { Qoptions } {#1}
    \Qoptions_question_header:VV \l__Qoptions_label_tl \l__Qoptions_sublabel_tl
    \group_end:
  }

\ExplSyntaxOff

\begin{document}
  \begin{questions}

    \myQFormat
    \question[15]\hspace*{0pt}\vspace*{\baselineskip}
    The output should be ``Question 1 [15 Marks]''

    \myQFormat[label = Part]
    \question[10]\hspace*{0pt}\vspace*{\baselineskip}
    The output should be ``Part 2 [10 Marks]''

    \myQFormat[label=Part, sublabel=Subtitle]
    \question[5]\hspace*{0pt}\vspace*{\baselineskip}
    The output should be ``Part 3 [Subtitle] [5 Marks]''

    \myQFormat[sublabel=Subtitle]
    \question[10]\hspace*{0pt}\vspace*{\baselineskip}
    The output should be ``Question 4 [Subtitle] [10 Marks]''

  \end{questions}
\end{document}

与上面相同的输出。

答案2

当你调用时\tl_if_blank:nTF { \l__Qoptions_label_tl }你总是会得到错误的结果,因为参数不为空。

使用新方法您只需执行\tl_use:N \l__Qoptions_label_tl,因为变量将始终包含所需的字符串:初始值或使用键指定的内容label

使用\IfValueT很好仅有的如果您传递了特定参数。使用新方法,您可以测试sublabel变量中存储的值是否为空(这意味着尚未设置)。您可以使用测试键是否sublabel已收到值\tl_if_blank:V(TF)(括号表示您可以使用TFTF并提供适当数量的参数)。

\documentclass[addpoints]{exam}
\usepackage{xparse}
\usepackage[xparse]{tcolorbox}

\renewcommand{\questionshook}{%
  \setlength{\leftmargin}{0pt}%
  \setlength{\labelwidth}{-\labelsep}%
}

\NewTColorBox{MarksTCBox} { O{} }{
    left skip= 0pt,
    right skip=0pt,
    left=2pt,
    right=2pt,
    capture=hbox,
    halign=center,
    valign=center,
    boxrule=0pt,
    arc=0pt,
    top=2pt,
    bottom=2pt,
    boxsep=0pt,
    nobeforeafter,
    box align = base,
    baseline=4pt,
    #1,
}

\ExplSyntaxOn

\keys_define:nn { Qoptions }
  {
    label       .tl_set:N  = \l__Qoptions_label_tl,
    label       .initial:n = Question,
    sublabel    .tl_set:N  = \l__Qoptions_sublabel_tl,
  }

\cs_new_protected:Npn \Qoptions_question_header:n #1
  {
    \qformat
      {
        % \question appears to create a group, so the options are duly cleared
        % when the question title has been typeset.
        \keys_set:nn { Qoptions } {#1}
        \textbf
          {
            \underline
              {
                \large
                \tl_use:N \l__Qoptions_label_tl
                \c_space_tl
                \thequestion
                \c_space_tl
                \tl_if_blank:VF \l__Qoptions_sublabel_tl
                  { [ \l__Qoptions_sublabel_tl ] \c_space_tl }
                \begin{MarksTCBox}
                    \scan_stop: [\totalpoints\ Marks]
                \end{MarksTCBox}
              }
          }
          \hfill % Otherwise, you'll have an Underfull \hbox for each question.
      }
  }

\NewDocumentCommand { \myQFormat } { O{} }
  {
    \Qoptions_question_header:n {#1}
  }

\ExplSyntaxOff

\begin{document}
  \begin{questions}

    \myQFormat
    \question[15]\hspace*{0pt}\vspace*{\baselineskip}
    The output should be ``Question 1 [15 Marks]''

    \myQFormat[label = Part]
    \question[10]\hspace*{0pt}\vspace*{\baselineskip}
    The output should be ``Part 2 [10 Marks]''

    \myQFormat[label=Part, sublabel=Subtitle]
    \question[5]\hspace*{0pt}\vspace*{\baselineskip}
    The output should be ``Part 3 [Subtitle] [5 Marks]''

    \myQFormat[sublabel=Subtitle]
    \question[10]\hspace*{0pt}\vspace*{\baselineskip}
    The output should be ``Question 4 [Subtitle] [10 Marks]''

  \end{questions}
\end{document}

相关内容