具有多个参数的 xparse 处理器

具有多个参数的 xparse 处理器

我想定义一个函数,该函数具有固定(三个)数量的可选参数,后面跟着可变数量的强制逗号分隔参数。每个强制参数都必须在彩色框中生成文本(三个可选参数定义框的颜色)。

遵循线程,我写了这个函数:

\NewDocumentCommand{\boxed}{O{white}O{gray}O{white}>{\SplitList{,}}m}{%
  \ProcessList{#4}{\func}}
\NewDocumentCommand{\func}{m}{%
  \fcolorbox{white}{gray}{\color{white}#1}\space}

上述函数生成所需的框,但忽略可选参数,因为我还没有找到将多个参数传递给函数

经过一些研究,我发现了这个解决方法:

\NewDocumentCommand{\boxed}{O{white}O{gray}O{white}>{\SplitList{,}}m}{%
  \def\@opta{#1}%
  \def\@optb{#2}%
  \def\@optc{#3}%
  \ProcessList{#4}{\func}}
\NewDocumentCommand{\func}{m}{%
  \fcolorbox{\@optc}{\@optb}{\color{\@opta}#1}\space}

上面的函数实现了我想要的功能,但我不相信没有更简单的方法来完成任务,而不需要那些丑陋的定义。 我错了吗?

答案1

\ProcessList功能是实验性的,并建议宏采用单个参数。解决此问题的一种方法是定义\funcwithin \boxed,以便它获取参数:

在此处输入图片描述

\documentclass{article}

\usepackage{xparse,xcolor}

\NewDocumentCommand{\boxed}{ O{white} O{gray} O{white} >{\SplitList{,}}m }{{%
  \NewDocumentCommand{\func}{ m }{%
    \fcolorbox{#3}{#2}{\color{#1}\strut##1}\space}
  \ProcessList{#4}{\func}}}

\begin{document}

\boxed{a,b,c}

\boxed[yellow]{d,e,f}

\boxed[yellow][black]{g,h,i}

\boxed[yellow][black][red]{j,k,l}

\end{document}

答案2

在这种情况下,最好使用较低级别的功能:

\documentclass{article}
\usepackage{xparse,xcolor}

\ExplSyntaxOn

\NewDocumentCommand{\myboxed}{O{white}O{gray}O{white}m}
 {
  \clist_map_inline:nn { #4 }
   {
    \andrea_myboxed:nnnn { #1 } { #2 } { #3 } { ##1 }
   }
 }
\cs_new_protected:Nn \andrea_myboxed:nnnn
 {
  \fcolorbox{#3}{#2}{\color{#1}#4}
 }
\ExplSyntaxOff

\begin{document}

\myboxed{a,b,c}

\end{document}

在此处输入图片描述

请注意,\clist_map_inline:nn将第一个参数在逗号处拆分,删除前导和尾随空格并循环遍历各个项目,将每个项目传递给第二个参数中的代码#1;这里之所以变成这样,是##1因为我们处于定义的主体中。

\seq_set_split:Nnn可以使用函数并使用来拆分逗号以外的其他字符\seq_map_inline:Nn。您可以在网站上找到几个示例。

但是,三个可选参数很麻烦,因为如果您只想指定第三个参数,则还必须明确提供前两个参数。键值接口更好。优点是能够以任何顺序指定键,因此您只需记住它们的名称(这比记住可选参数的顺序更容易)。

\documentclass{article}
\usepackage{xparse,xcolor}

\ExplSyntaxOn

\keys_define:nn { andrea/myboxed }
 {
  border     .tl_set:N = \l__andrea_myboxed_border_tl,
  background .tl_set:N = \l__andrea_myboxed_background_tl,
  text       .tl_set:N = \l__andrea_myboxed_text_tl,
  border     .initial:n = white,
  background .initial:n = gray,
  text       .initial:n = white,
 }
\NewDocumentCommand{\kmyboxed}{O{}m}
 {
  \group_begin:
  \keys_set:nn { andrea/myboxed } { #1 }
  \clist_map_inline:nn { #2 }
   {
    \andrea_myboxed:VVVn
     \l__andrea_myboxed_border_tl
     \l__andrea_myboxed_background_tl
     \l__andrea_myboxed_text_tl
     {##1}
   }
  \group_end:
 }
\cs_new_protected:Nn \andrea_myboxed:nnnn
 {
  \fcolorbox{#3}{#2}{\color{#1}#4}
 }
\cs_generate_variant:Nn \andrea_myboxed:nnnn { VVV }
\ExplSyntaxOff

\begin{document}

\kmyboxed{a,b,c}

\kmyboxed[text=red,background=green,border=blue]{a,b,c}

\end{document}

在此处输入图片描述

我们定义一些键,设置它们的初始值,并基本上执行与之前相同的代码,但在一个组中,以便在特定循环完成时保持值不变。如果组妨碍了,可以在 处重置初始值\keys_set:nn

变体\andrea_myboxed:VVVn用于将标记列表变量转换为括号参数(其值位于括号之间);在这个特定的应用程序中不是必需的,但在其他应用程序中可以是必需的。

答案3

我认为\ProcessList必须从xparse文档。您始终可以使用\ExplSyntaxOn \ExplSyntaxOff(毕竟是xparse加载)并与等配合使用,以获得如下所示的完整解决方案。expl3\tl_set:Nn \l_boxed_opta_tl {#1}

\documentclass{article}
\usepackage{xcolor,xparse}

\ExplSyntaxOn
\tl_new:N \l_boxed_opta_tl
\tl_new:N \l_boxed_optb_tl
\tl_new:N \l_boxed_optc_tl

\NewDocumentCommand{\boxed}{O{white}O{gray}O{white}>{\SplitList{,}}m}{
    \tl_set:Nn \l_boxed_opta_tl {#1}
    \tl_set:Nn \l_boxed_optb_tl {#2}
    \tl_set:Nn \l_boxed_optc_tl {#3}
    \ProcessList{#4}{\boxed_func:n}
}

\cs_new:Npn \boxed_func:n #1 {
    \fcolorbox{\l_boxed_optc_tl}{\l_boxed_optb_tl}{\color{\l_boxed_opta_tl}#1}\space
}
\ExplSyntaxOff

\begin{document}
\boxed{a,b,c}
\end{document}

在此处输入图片描述

相关内容