如何在“模块”中设置密钥并将其余密钥传递给 l3keys 中的“模块/子组”?

如何在“模块”中设置密钥并将其余密钥传递给 l3keys 中的“模块/子组”?

我正在尝试创建一个基于布尔条件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:nnregex模块从逗号列表中过滤出给定的选项。在下面的示例中,我们过滤出该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-amymodule / 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}

相关内容