设置`l3keys`时如何区分“无值”和“空值”?

设置`l3keys`时如何区分“无值”和“空值”?

我正在尝试创建一个选项l3keys,如果它收到一个值,即使是一个空值,它也会添加到属性列表中,但如果它没有收到任何值,它就会从属性列表中删除。

但是,我似乎无法在“操作”中区分。我知道可以key捕获这种情况,但它不能接收代码块,只能接收值。我也知道我可以在中区分这种情况,但我希望在整个集合中的某些选项中实现这种行为,而对整个事物使用会变得复杂。key=.code:n.default:n\keyval_parse:nnn\keyval_parse:nnn

MWE 说明了这种情况:

\documentclass{article}

\ExplSyntaxOn
\prop_new:N \l__myprops_prop
\keys_define:nn { options }
  {
    mykey .code:n =
      {
        \tl_if_novalue:nTF {#1}
          { \prop_remove:Nn \l__myprops_prop { mykey } }
          { \prop_put:Nnn \l__myprops_prop { mykey } {#1} }
        \prop_show:N \l__myprops_prop
      } ,
    mykey2 .code:n =
      {
        \tl_if_empty:nTF {#1}
          { \prop_remove:Nn \l__myprops_prop { mykey2 } }
          { \prop_put:Nnn \l__myprops_prop { mykey2 } {#1} }
        \prop_show:N \l__myprops_prop
      }
  }
\ExplSyntaxOff

\begin{document}

\ExplSyntaxOn
\keys_set:nn { options } { mykey }
\keys_set:nn { options } { mykey= }
\keys_set:nn { options } { mykey=val }
\prop_clear:N \l__myprops_prop
\keys_set:nn { options } { mykey2 }
\keys_set:nn { options } { mykey2= }
\keys_set:nn { options } { mykey2=val }
\ExplSyntaxOff

\end{document}

本文档的日志包含:

The property list \l__myprops_prop contains the pairs (without outer braces):
>  {mykey}  =>  {}.
<recently read> }
                 
l.27 \keys_set:nn { options } { mykey }
                                       
The property list \l__myprops_prop contains the pairs (without outer braces):
>  {mykey}  =>  {}.
<recently read> }
                 
l.28 \keys_set:nn { options } { mykey= }
                                        
The property list \l__myprops_prop contains the pairs (without outer braces):
>  {mykey}  =>  {val}.
<recently read> }
                 
l.29 \keys_set:nn { options } { mykey=val }
                                           
The property list \l__myprops_prop is empty
> .
<recently read> }
                 
l.31 \keys_set:nn { options } { mykey2 }
                                        
The property list \l__myprops_prop is empty
> .
<recently read> }
                 
l.32 \keys_set:nn { options } { mykey2= }
                                         
The property list \l__myprops_prop contains the pairs (without outer braces):
>  {mykey2}  =>  {val}.
<recently read> }
                 
l.33 \keys_set:nn { options } { mykey2=val }

这表明key和 都没有key=通过“无值”测试,而 和 都key通过key=了空值测试。不幸的是,我无法使用空值来“表示”删除,因为“空”是所讨论键的有效值。这确实是\keyval_parse:nnn这里唯一的选择吗?

答案1

这建立在与 @Phelype 的答案相同的基本思想上,即用作\c_novalue_tl标记,但不是环绕\keyval_parse:nnn\keys_set:nn,而是使用.default:x处理程序将默认值设置为\c_novalue_tl

\documentclass{article}

\ExplSyntaxOn
\prop_new:N \l__myprops_prop
\cs_new_protected:Npn \__myprops_handle:n #1
  {
    \tl_if_novalue:nTF {#1}
      { \prop_remove:NV \l__myprops_prop \l_keys_key_str }
      { \prop_put:NVn   \l__myprops_prop \l_keys_key_str {#1} }
    \prop_show:N \l__myprops_prop
  }
\keys_define:nn { options }
  {
     mykey  .code:n = \__myprops_handle:n {#1}
    ,mykey  .default:x = \c_novalue_tl
    ,mykey2 .code:n = \__myprops_handle:n {#1}
    ,mykey2 .default:x = \c_novalue_tl
  }
\ExplSyntaxOff

\begin{document}

\ExplSyntaxOn
\keys_set:nn { options } { mykey }
\keys_set:nn { options } { mykey= }
\keys_set:nn { options } { mykey=val }
\prop_clear:N \l__myprops_prop
\keys_set:nn { options } { mykey2 }
\keys_set:nn { options } { mykey2= }
\keys_set:nn { options } { mykey2=val }
\ExplSyntaxOff

\end{document}

答案2

没有内置方法来区分mykey何时mykey={}使用处理程序进行声明.code:n。在内部,这些情况是不同的,并且有一个布尔变量可以跟踪这些情况,但所有变量都使用来自的私有变量l3keys

您可以使用可用的接口来执行的操作是使用\keyval_parse:nnn,正如您所建议的那样,区分两种情况,然后在mykey使用 时将其转换为mykey = \c_novalue_tl,然后密钥中的代码可以检测到使用\tl_if_novalue:nTF。这使得解析比仅使用 慢一点,\keys_set:nn因为 中的一些常见簿记代码\keys_set:nn执行得更频繁,但这可能是最小的。

下面的示例实现了,如果没有给出值,\gusbrs_keys_set:nn则传递给一个键:\c_novalue_tl

\documentclass{article}

\ExplSyntaxOn
\cs_new_protected:Npn \gusbrs_keys_set:nn #1 #2
  {
    \keyval_parse:nnn
      { \__gusbrs_keys_set:nn {#1} }
      { \__gusbrs_keys_set:nnn {#1} }
        {#2}
  }
\cs_new_protected:Npn \__gusbrs_keys_set:nn #1 #2
  { \use:x { \keys_set:nn {#1} { #2 = \c_novalue_tl } } }
\cs_new_protected:Npn \__gusbrs_keys_set:nnn #1 #2 #3
  { \keys_set:nn {#1} { #2 = #3 } }
\ExplSyntaxOff


\ExplSyntaxOn
\prop_new:N \l__myprops_prop
\keys_define:nn { options }
  {
    mykey .code:n =
      {
        \tl_if_novalue:nTF {#1}
          { \prop_remove:Nn \l__myprops_prop { mykey } }
          { \prop_put:Nnn \l__myprops_prop { mykey } {#1} }
        \prop_show:N \l__myprops_prop
      } ,
  }
\ExplSyntaxOff

\begin{document}

\ExplSyntaxOn
\gusbrs_keys_set:nn { options } { mykey }
\gusbrs_keys_set:nn { options } { mykey= }
\gusbrs_keys_set:nn { options } { mykey=val }
\ExplSyntaxOff

\end{document}

这打印在终端上:

The property list \l__myprops_prop is empty
> .
<recently read> }
                 
l.35 \gusbrs_keys_set:nn { options } { mykey }
                                              
? 
The property list \l__myprops_prop contains the pairs (without outer braces):
>  {mykey}  =>  {}.
<recently read> }
                 
l.36 \gusbrs_keys_set:nn { options } { mykey= }
                                               
? 
The property list \l__myprops_prop contains the pairs (without outer braces):
>  {mykey}  =>  {val}.
<recently read> }
                 
l.37 \gusbrs_keys_set:nn { options } { mykey=val }
                                                  
?

相关内容