我想定义一个函数,该函数具有固定(三个)数量的可选参数,后面跟着可变数量的强制逗号分隔参数。每个强制参数都必须在彩色框中生成文本(三个可选参数定义框的颜色)。
遵循这线程,我写了这个函数:
\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
功能是实验性的,并建议宏采用单个参数。解决此问题的一种方法是定义\func
within \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}