如何保存包含 expl3 中的键值选项的键值选项?

如何保存包含 expl3 中的键值选项的键值选项?

我有一个使用键值语法的命令。例如,如果需要,它包含带有各种选项的图像。

我正在使用 expl3 键值处理。

我想将键值设置保存到全局标记列表中,以便下次执行命令时可以重新使用它们作为默认值。我找不到明显的方法来做到这一点,因为我不想将宏的键值选项设置为全局,因为将它们设置为全局会使事情以各种方式复杂化。我想要的只是将相关的键值保存到全局标记列表中,以便我可以重复使用它们。(我不在乎它是否是标记列表 - 这似乎是显而易见的选择。)

看起来我可以很好地保存布尔值和逗号分隔列表,但我对本身就是键值选项列表的标记列表有困难。例如,graphics={<key-value options>}用于将设置传递给\includegraphics。但是,我无法让它工作。

这是一个(相对)最小的例子,这使得我为什么要在金星上这样做变得完全不明显,但这对你来说就是小型化。

\documentclass{article}
\usepackage{xparse,graphicx}
\begin{document}
\ExplSyntaxOn
\tl_new:N \l_pre_graphics_tl
\tl_new:N \g_pre_img_options_tl
\tl_new:N \g_pre_img_tl
\cs_new_protected_nopar:Nn \pre_key_tl_save:Nn
{
  \tl_if_empty:cF {l_pre_#2_tl}
    {
      \tl_gput_right:No #1 { #2 = }
      \tl_gput_right:NV #1 \c_left_brace_str
      \tl_gput_right:Nv #1 { l_pre_#2_tl }
      \tl_gput_right:NV #1 \c_right_brace_str
      \tl_gput_right:Nn #1 { , }
    }
}
\cs_generate_variant:Nn \tl_gput_right:Nn {Nv}
% includegraphics bit courtesy of egreg (chat 2015-01-08)
\cs_new:Npn \pre_includegraphics:nn #1 #2
 {
  \includegraphics[#1]{#2}
 }
\cs_generate_variant:Nn \pre_includegraphics:nn { VV }
\keys_define:nn { pre / img }
{
  graphics .tl_set:N = \l_pre_graphics_tl,
}
\NewDocumentCommand \incimg { o m }
{
  \group_begin:
    \tl_if_empty:NF \g_pre_img_options_tl
    {
      \keys_set:nV { pre / img } \g_pre_img_options_tl
    }
    \IfValueT{#1}{ \keys_set:nn { pre / img } { #1 } }
    \pre_key_tl_save:Nn \g_pre_img_options_tl { graphics }
    \tl_set:Nn \g_pre_img_tl { #2 }
    \pre_includegraphics:VV \l_pre_graphics_tl \g_pre_img_tl
  \group_end:
}
\ExplSyntaxOff

\incimg[
  graphics={width=\textwidth},
]{example-image-a}
\incimg[
  graphics={width=\textwidth},
]{example-image-a}
\end{document}

错误信息建议我向人寻求帮助,所以我来了......

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! LaTeX error: "kernel/misplaced-equals-sign"
! 
! Misplaced equals sign in key-value input 194
! 
! See the LaTeX3 documentation for further information.
! 
! For immediate help type H <return>.
!...............................................  

l.194 ]{example-image-a}

? h
|'''''''''''''''''''''''''''''''''''''''''''''''                                                                                              
| LaTeX is attempting to parse some key-value input but found two equals signs                                                                
| not separated by a comma.                                                                                                                   
|...............................................                                                                                              
? h                                                                                                                                           
Sorry, I already gave what help I could...                                                                                                    
Maybe you should try asking a human?                                                                                                          
An error might have occurred before I noticed any problems.                                                                                   
``If all else fails, read the instructions.''                                                                                                 

?   

如果我在尝试使用令牌之前显示令牌列表,我会得到

> \g_pre_img_options_tl=graphics={width=\textwidth },.

这让我这个头脑简单的人意识到我需要以某种方式在列表周围添加花括号。但是,到目前为止,我这样做的尝试都没有成功。要么 LaTeX 会查找不属于键的内容(例如\g_pre_img_options),要么括号就会消失。

答案1

我不完全明白您想要实现什么,无论我猜测什么,我认为我不会以同样的方式去做,但是,无论如何,这里有一个使该文档编译的更改。

\cs_new_protected_nopar:Nn \pre_key_tl_save:Nn
{
  \tl_if_empty:cF {l_cfr_#2_tl}
    {
      \tl_gput_right:No #1 { #2 = }
      \tl_gput_right:NV #1 \c_left_brace_str
      \tl_gput_right:Nv #1 { l_pre_#2_tl }
      \tl_gput_right:NV #1 \c_right_brace_str
      \tl_gput_right:Nn #1 { , }
    }
}

这似乎是错误的,即使我不太清楚,但首先,问题过于复杂,包含许多不同的部分,而且你实际上无法做到这一点(添加\c_left_brace_str不是添加打开组 catcode 1 {,而是添加 catcode“其他”,类似于)。使用简单的参数和正确的\string{会更简单。x\exp_not:*

\cs_new_protected_nopar:Nn \pre_key_tl_save:Nn
 {
  \tl_if_empty:cF {l_cfr_#2_tl}
   {
    \tl_gput_right:Nx #1 { #2 = { \exp_not:v { l_pre_#2_tl } } , }
   }
 }

经过这个改变它至少可以编译,但我不知道这是否能解决所有问题。


您想将一个字符串和一个宏的值添加到另一个宏中。最简单的方法是使用参数一次性完成所有操作x。它实际上是在做您想做的事情,但是正确的。\tl_put_right:Nx扩展第二个参数\edef,也就是说,它扩展了一切,因此您只需要在您想要的精确时刻停止即可。替换参数后,您最终会得到

\tl_gput_right:Nx \g_pre_img_options_tl { graphics = { \exp_not:v { l_pre_grahpics_tl } } , }

如果你看到了,\edef\foo{graphics={foo}}你就会明白的内容是什么\foo:什么都不会扩展,字母也不会扩展,其他的也不会扩展(“=”),括号{和也不会扩展}。所以魔法就在里面\exp_not:v { l_pre_grahpics_tl }。多亏了 expl3 参数,它与 完全相同,而\exp_not:V \l_pre_grahpics_tl又与 完全相同,\exp_not:n { width=\textwidth }只是在那里停止了扩展(\exp_not:n\unexpanded)。

这样,上面的那行在x扩展之后就变成了

\tl_gput_right:Nn \g_pre_img_options_tl { graphics = { width = \textwidth } , }

如果不是因为\unexpanded{width=\textwidth}TeX 可能会尝试像任何其他宏一样进行扩展\textwidth,而这(现在不确定)可能已经扩展,\dimen <number>并且一般来说,我们不希望发生这种扩展。

抱歉,但任何人都可以自由编辑这个答案,但它并不完美。

相关内容