我正在尝试创建一个基于布尔条件key
传递其余键的函数/subgroup
。也就是说,类似下面的代码可以工作:
[key in <module>, rest of keys pass to <module/subgroup>]
每个/subgroup
键都有相同名称的键,我的想法是能够创建一个以以下方式工作的命令:
\mycmd[key = name (active condition), pass rest of keys acorde to condition to <module/name>]{...}
使用我自己的代码,我可以做到这一点,但它基于字符串的比较,非常薄弱,如果放置顺序不正确,则会失败。这是示例文件(第一次尝试):
\documentclass[10pt]{article}
\usepackage{xparse}
\ExplSyntaxOn
\keys_define:nn { mymodule / style-a }
{
style-a .bool_set:N = \l_style_a_bool,
style-a .initial:n = false,
key-a .tl_set:N = \l_style_a_keya_tl,
key-b .tl_set:N = \l_style_a_keyb_tl
}
\keys_define:nn { mymodule / style-b }
{
style-b .bool_set:N = \l_style_b_bool,
style-b .initial:n = false,
key-a .tl_set:N = \l_style_b_keya_tl,
key-b .tl_set:N = \l_style_b_keyb_tl,
}
\keys_define:nn { mymodule }
{
style-a .code:n = \keys_set:nn { mymodule / style-a } { style-a = true },
style-b .code:n = \keys_set:nn { mymodule / style-b } { style-b = true }
}
% style-a
\cs_new_protected:Npn \__mymodule_style_a:n #1
{
This ~ is ~ \texttt{"#1"} ~ whit ~ \texttt{[key-a ~ = ~ \use:c{l_style_a_keya_tl}]} ~
and ~ \texttt{[key-b ~ = ~ \use:c{l_style_a_keyb_tl}]} .
}
% style-b
\cs_new_protected:Npn \__mymodule_style_b:n #1
{
This ~ is ~ \texttt{"#1"} ~ whit ~ \texttt{[key-a ~ = ~ \use:c{l_style_b_keya_tl}]} ~
and ~ \texttt{[key-b ~ = ~ \use:c{l_style_b_keyb_tl}]} .
}
\cs_new_protected:Npn \__mymodule_test_keys:n #1
{
\str_case:xnF { \clist_item:nn { #1 } { 1 } }
{
{ style-a }
{
\keys_set:nn { mymodule } { style-a }
\keys_set:nn { mymodule / style-a } { #1 }
}
{ style-b }
{
\keys_set:nn { mymodule } { style-b }
\keys_set:nn { mymodule / style-b } { #1 }
}
}
{}
}
\cs_generate_variant:Nn \str_case:nnF { x }
\cs_new_protected:Npn \mycmd:nn #1#2
{
\group_begin:
\__mymodule_test_keys:n { #1 }
\bool_if:nT
{
\l_style_a_bool
}
{ \__mymodule_style_a:n { #2 } }
\bool_if:nT
{
\l_style_b_bool
}
{ \__mymodule_style_b:n { #2 } }
\group_end:
}
\NewDocumentCommand{\mycmd}{ o m }
{
\mycmd:nn{#1}{#2}
}
\ExplSyntaxOff
\begin{document}
\mycmd[style-a,key-a=value-A,key-b=value-A]{style-a}\par
\mycmd[style-b,key-a=value-B,key-b=value-B]{style-b}
\end{document}
第二次尝试解决了第一次尝试的问题,但是,失去了生成错误消息的可能性。这是第二个示例文件:
\documentclass[10pt]{article}
\usepackage{xparse}
\ExplSyntaxOn
% define bools for keys
\bool_new:N \l_style_a_bool
\bool_new:N \l_style_b_bool
\keys_define:nn { mymodule / style-a }
{
style .tl_set:N = \l_tmpa_tl ,
key-a .tl_set:N = \l_style_a_keya_tl,
key-b .tl_set:N = \l_style_a_keyb_tl,
}
\keys_define:nn { mymodule / style-b }
{
style .tl_set:N = \l_tmpa_tl ,
key-a .tl_set:N = \l_style_b_keya_tl,
key-b .tl_set:N = \l_style_b_keyb_tl,
}
\keys_define:nn { mymodule }
{
style .choice: ,
style / style-a .code:n = { \bool_set_true:N \l_style_a_bool } ,
style / style-b .code:n = { \bool_set_true:N \l_style_b_bool } ,
unknown .code:n = {} %
}
% style-a
\cs_new_protected:Npn \__mymodule_style_a:n #1
{
This ~ is ~ \texttt{"#1"} ~ whit ~ \texttt{[key-a ~ = ~ \use:c{l_style_a_keya_tl}]} ~
and ~ \texttt{[key-b ~ = ~ \use:c{l_style_a_keyb_tl}]} .
}
% style-b
\cs_new_protected:Npn \__mymodule_style_b:n #1
{
This ~ is ~ \texttt{"#1"} ~ whit ~ \texttt{[key-a ~ = ~ \use:c{l_style_b_keya_tl}]} ~
and ~ \texttt{[key-b ~ = ~ \use:c{l_style_b_keyb_tl}]} .
}
\cs_new_protected:Npn \mycmd:nn #1#2
{
\group_begin:
\keys_set:nn { mymodule } { #1 }
\bool_if:nT
{
\l_style_a_bool
}
{
\keys_set:nn { mymodule / style-a } { #1 }
\__mymodule_style_a:n {#2}
}
\bool_if:nT
{
\l_style_b_bool
}
{
\keys_set:nn { mymodule / style-b } { #1 }
\__mymodule_style_b:n {#2}
}
\group_end:
}
\NewDocumentCommand{\mycmd}{ o m }
{
\mycmd:nn{#1}{#2}
}
\ExplSyntaxOff
\begin{document}
\mycmd[style=style-a,key-a=value-A,key-b=value-A]{style-a}\par
\mycmd[style=style-b,key-a=value-B,key-b=value-B]{style-b}
\end{document}
我在论坛上搜索了一些自适应代码,但没有找到。有什么办法吗?
问候。
答案1
您可以借助\clist_map_inline:nn
和regex
模块从逗号列表中过滤出给定的选项。在下面的示例中,我们过滤出该style
选项的所有出现情况:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\regex_new:N \l__mymodule_option_regex
% Filter-out all occurrences of keyword argument #1 from comma list #2.
% Store the resulting comma list in #3.
\cs_new_protected:Npn \__mymodule_filter_out_option:nnN #1#2#3
{
\tl_set:Nn \l_tmpa_tl {#1}
\regex_set:Nn \l__mymodule_option_regex { ^ \u{l_tmpa_tl} \ * = }
\clist_clear:N #3
\clist_map_inline:nn {#2}
{
\regex_match:NnF \l__mymodule_option_regex {##1}
{ \clist_put_right:Nn #3 {##1} }
}
}
% Filter-out all occurrences of keyword argument #1 from comma list #2.
% Print the remaining items, one per line.
\NewDocumentCommand \filteroutoption { m m }
{
\__mymodule_filter_out_option:nnN {#1} {#2} \l_tmpa_clist
\clist_use:Nn \l_tmpa_clist { \\ }
}
\ExplSyntaxOff
\begin{document}
\noindent
\filteroutoption{style}{style=style-a,key-a=value-A,key-b=value-B,
foobarstyle = foobarvalue,
style = other-style, some-key=value,
other key = {other, value}, style=foo-style,
final key = {its\ \ \ \ value}}
\end{document}
为了在第二个示例中使用它,您可以替换:
\cs_new_protected:Npn \mycmd:nn #1#2
{
\group_begin:
\keys_set:nn { mymodule } { #1 }
\bool_if:nT
{
\l_style_a_bool
}
{
\keys_set:nn { mymodule / style-a } { #1 }
\__mymodule_style_a:n {#2}
}
\bool_if:nT
{
\l_style_b_bool
}
{
\keys_set:nn { mymodule / style-b } { #1 }
\__mymodule_style_b:n {#2}
}
\group_end:
}
\NewDocumentCommand{\mycmd}{ o m }
{
\mycmd:nn{#1}{#2}
}
和:
\clist_new:N \l__mymodule_tmp_clist
\cs_new_protected:Npn \mymodule_mycmd:nn #1#2
{
\group_begin:
\__mymodule_filter_out_option:nnN { style } {#1} \l__mymodule_tmp_clist
\keys_set:nn { mymodule } {#1}
\bool_if:NT \l_style_a_bool
{
\keys_set:nV { mymodule / style-a } \l__mymodule_tmp_clist
\__mymodule_style_a:n {#2}
}
\bool_if:NT \l_style_b_bool
{
\keys_set:nV { mymodule / style-b } \l__mymodule_tmp_clist
\__mymodule_style_b:n {#2}
}
\group_end:
}
\NewDocumentCommand \mycmd { O{} m }
{
\mymodule_mycmd:nn {#1} {#2}
}
这样,mymodule / style-a
就mymodule / style-b
不会收到任何style
密钥。
你的第二个例子可以改成这样:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
% define bools for keys (by def false)
\bool_new:N \l_style_a_bool
\bool_new:N \l_style_b_bool
\keys_define:nn { mymodule / style-a }
{
key-a .tl_set:N = \l_style_a_keya_tl,
key-b .tl_set:N = \l_style_a_keyb_tl,
}
\keys_define:nn { mymodule / style-b }
{
key-a .tl_set:N = \l_style_b_keya_tl,
key-b .tl_set:N = \l_style_b_keyb_tl,
}
\keys_define:nn { mymodule }
{
style .choice: ,
% Remember to set the bools to their default value before using
% a \keys_set-like function here (alas, .bool_set:N \l_style_*_bool
% doesn't seem to be accepted here).
style / style-a .code:n = { \bool_set_true:N \l_style_a_bool } ,
style / style-b .code:n = { \bool_set_true:N \l_style_b_bool } ,
}
% style-a
\cs_new_protected:Npn \__mymodule_style_a:n #1
{
This ~ is ~ \texttt{"#1"} ~ with ~ \texttt{[key-a ~ = ~ \use:c{l_style_a_keya_tl}]} ~
and ~ \texttt{[key-b ~ = ~ \use:c{l_style_a_keyb_tl}]} .
}
% style-b
\cs_new_protected:Npn \__mymodule_style_b:n #1
{
This ~ is ~ \texttt{"#1"} ~ with ~ \texttt{[key-a ~ = ~ \use:c{l_style_b_keya_tl}]} ~
and ~ \texttt{[key-b ~ = ~ \use:c{l_style_b_keyb_tl}]} .
}
\msg_new:nnn { mymodule } { unknown-style }
{
The ~ choice ~ passed ~ to ~ key ~ [style] ~ is ~ not ~ valid. ~
Valid ~ choices ~ are: ~ style-a, ~ style-b.
}
\tl_new:N \l__mymodule_styles_tl
% Filter-out all occurrences of keyword argument #1 from comma list #2.
% Store the resulting comma list in #3.
\cs_new_protected:Npn \__mymodule_filter_out_option:nnN #1#2#3
{
\tl_set:Nn \l_tmpa_tl {#1}
\regex_set:Nn \l__mymodule_option_regex { ^ \u{l_tmpa_tl} \ * = }
\clist_clear:N #3
\clist_map_inline:nn {#2}
{
\regex_match:NnF \l__mymodule_option_regex {##1}
{ \clist_put_right:Nn #3 {##1} }
}
}
\clist_new:N \l__mymodule_tmp_clist
\cs_new_protected:Npn \mymodule_mycmd:nn #1#2
{
\group_begin:
\bool_set_false:N \l_style_a_bool
\bool_set_false:N \l_style_b_bool
\keys_set_known:nn { mymodule } {#1}
\__mymodule_filter_out_option:nnN { style } {#1} \l__mymodule_tmp_clist
\bool_if:NT \l_style_a_bool
{
\keys_set:nV { mymodule / style-a } \l__mymodule_tmp_clist
\__mymodule_style_a:n {#2}
}
\bool_if:NT \l_style_b_bool
{
\keys_set:nV { mymodule / style-b } \l__mymodule_tmp_clist
\__mymodule_style_b:n {#2}
}
\group_end:
}
\NewDocumentCommand \mycmd { O{} m }
{
\mymodule_mycmd:nn {#1} {#2}
}
\ExplSyntaxOff
\begin{document}
% check with valid keys
\mycmd[style=style-a,key-a=value-A,key-b=value-A]{style-a}\par
\mycmd[key-a=value-B,key-b=value-B,style=style-b]{style-b}
% Uncomment to show error :)
%\mycmd[foobarstyle=style-aandotherthings, style=style-a,key-a=value-A,key-b=value-A]{style-a}\par
%\mycmd[style=style-c,key-a=value-B,key-b=value-B]{style-b}
\end{document}