我该如何写出 Expl3 等效内容?

我该如何写出 Expl3 等效内容?

我有一个命令可以容易地xparse使用、etoolbox和 等多种资源进行编写pgffor

\documentclass{article}
\usepackage{amsmath}
\usepackage{etoolbox}
\usepackage{xparse}
\usepackage{pgffor}

\makeatletter

\def\ae@tmp@frontmatter{}
\def\ae@list{}
\NewDocumentCommand\qchoice{ mom }
  {%%
    \def\ae@tmp@frontmatter{#2}
    \let\ae@list\relax
    \foreach \myn in {#3}
    {%%
      \ifx\ae@list\relax
        \xdef\ae@list{\noexpand#1{\expandonce\ae@tmp@frontmatter\expandonce\myn}}%%
      \else
        \xdef\ae@list{\expandonce\ae@list
                      \noexpand\par
                      \noexpand#1{\expandonce\ae@tmp@frontmatter\expandonce\myn}}%%
      \fi
    }%%
    \ae@list}

\makeatother

\newcommand\aebf[1]{$\rightarrow$ \textbf{#1} DONE}
\pagestyle{empty}
\begin{document}

\qchoice\aebf[front matter::]{a,b,c,d}

\end{document}

但是,我希望能够使用Expl3语法编写与上述相同的代码。(除其他外,将\makeatletterxparsejust 结合使用似乎从哲学上来说错误的。)

看来我应该能够做到这一点,而不必使用pgfforetoolbox。但我一直遇到问题。

这是我最近的尝试:

\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}

\ExplSyntaxOn

\tl_new:N  \l_qchoice_command_sequence_tl
\tl_new:N  \l_qchoice_front_matter_tl
\tl_new:N  \l_qchoice_csv_choices_tl
\tl_new:N  \l_qchoice_tmp_tl
\seq_new:N \l_qchoice_choices_seq 

\NewDocumentCommand\qchoice{ mom }
  {%%
    \tl_set:Nn  \l_qchoice_command_sequence_tl {#1}
    \tl_clear:N \l_qchoice_front_matter_tl
    \tl_clear:N \l_qchoice_csv_choices_tl
    \IfNoValueF{#2}
      {
        \tl_set:Nn \l_qchoice_front_matter_tl {#2}
      }
    \seq_set_split:Nnn   \l_qchoice_choices_seq {,} {#3}
    \seq_map_function:NN \l_qchoice_choices_seq \qchoice_parse_choices:n
    \l_qchoice_csv_choices_tl
  }

\cs_new:Npn \qchoice_parse_choices:n #1 
  {
    \tl_clear:N      \l_qchoice_tmp_tl
    \tl_set:No       \l_qchoice_tmp_tl \l_qchoice_front_matter_tl
    \tl_put_right:Nn \l_qchoice_tmp_tl {#1}
    \tl_set:No       \l_qchoice_tmp_tl {{\l_qchoice_tmp_tl}}
    \tl_put_left:Nn  \l_qchoice_tmp_tl  \l_qchoice_command_sequence_tl
    \tl_if_empty:NTF \l_qchoice_csv_choices_tl
      {
        \tl_set:No        \l_qchoice_csv_choices_tl \l_qchoice_tmp_tl
      }
      {
        \tl_put_right:Nn  \l_qchoice_csv_choices_tl {\par}
        \tl_put_right:No  \l_qchoice_csv_choices_tl {\l_qchoice_tmp_tl}
      }
  }

\ExplSyntaxOff

\newcommand\aebf[1]{$\rightarrow$ \textbf{#1} DONE}
\pagestyle{empty}
\begin{document}

\qchoice\aebf[front matter::]{a,b,c,d}

\end{document}

线路似乎有问题

    \tl_set:No       \l_qchoice_tmp_tl {{\l_qchoice_tmp_tl}}

导致超出 TeX 容量错误。但语法对我来说似乎没问题,因为\l_qchoice_tmp_tl应该扩展一次,然后将其内容分配回\l_qchoice_tmp_tl。但这似乎不是正在发生的事情。

代码Expl3似乎变得非常复杂,如果这仅仅是因为我限制自己只使用LaTeX3资源,那么这没问题。

更新

最终我想要做的是

\qchoices<control sequence>[<optional front matter>]{<item a>,<item b>,<item c>,<item d>}

会产生一串像

<control sequence>{<optional front matter><item a>}<inter-item matter>
<control sequence>{<optional front matter><item b>}<inter-item matter>
<control sequence>{<optional front matter><item c>}<inter-item matter>
<control sequence>{<optional front matter><item d>}

在上面的例子中,我将其用作\par我的<inter-item matter>。请注意,<inter-item matter>不应跟在传递的最后一项之后。

我在使用Expl3代码时遇到的困难是将要传递的内容括<control sequence>在括号中。

答案1

虽然您可以一次构建一部分结果,但我会安排x使用映射在 -type 扩展中完成整个工作。由于输入是逗号列表,因此直接执行此操作可能最容易

\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}

\ExplSyntaxOn
\tl_new:N \l_qchoice_choices_tl
\cs_new:Npn \__qhoice_tmp:n #1 { }
\NewDocumentCommand \qchoice { m o m }
  {
    \tl_clear:N \l_qchoice_csv_tl
    \cs_set:Npn \__qhoice_tmp:n ##1
      {
        \exp_not:N #1
          {
            \IfNoValueF {#2} { \exp_not:n {#2} }
            \exp_not:n {##1}
          }
        \exp_not:N \par
      }
    \tl_set:Nx \l_qchoice_csv_tl
      {
        \clist_map_function:nN {#3}\__qhoice_tmp:n
      }
    \tl_show:N \l_qchoice_csv_tl
  }
\ExplSyntaxOff

\newcommand\aebf[1]{$\rightarrow$ \textbf{#1} DONE}
\pagestyle{empty}
\begin{document}

\qchoice\aebf[front matter::]{a,b,c,d}

\end{document}

如果您不希望分隔符出现在最后一项之后,有几种方法。概念上最简单的方法可能是使用内联映射,其中有一个测试来查看列表是否为空:在这种情况下,不要添加分隔符。

\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}

\ExplSyntaxOn
\tl_new:N \l_qchoice_choices_tl
\cs_new:Npn \__qhoice_tmp:n #1 { }
\NewDocumentCommand \qchoice { m o m }
  {
    \tl_clear:N \l_qchoice_csv_tl
    \clist_map_inline:nn {#3}
      {
        \tl_set:Nx \l_qchoice_csv_tl
          {
            \exp_not:V \l_qchoice_csv_tl
            \tl_if_empty:NF \l_qchoice_csv_tl
              { \exp_not:N \par }
            \exp_not:N #1
              {
                \IfNoValueF {#2} { \exp_not:n {#2} }
                \exp_not:n {##1}
              }
          }
      }
    \tl_show:N \l_qchoice_csv_tl
  }
\ExplSyntaxOff

\newcommand\aebf[1]{$\rightarrow$ \textbf{#1} DONE}
\pagestyle{empty}
\begin{document}

\qchoice\aebf[front matter::]{a,b,c,d}

\end{document}

这种方法需要每个项目分配一个任务:如果需要更高的效率,那么还有其他选择(问题表明列表很短)。

正如评论中所述,\tl_set:No \l_tmpa_tl { { \l_tmpa_tl } }尝试扩展{\l_tmpa_tl\tl_set:No处于较低级别并相当于\exp_after:wN \tl_set:Nn \exp_after:wN)。通常,如果您可以使用 -type 扩展一次性完成工作,最好避免一次构建复杂的标记列表x:只需要一次分配,这可以提高性能。

相关内容