我正在尝试在 expl3 中定义一个带有参数的本地函数,其中该函数的替换文本应该是标记列表变量的内容。
我目前的方法是
\tl_set:Nn \l_tmpa_tl { \textbf{##1} }
\exp_args:NNnV \cs_set:Npn \foo {##1} \l_tmpa_tl
\cs_show:N \foo
预期输出如下
\foo #1:->\textbf {#1}
但结果是
! Illegal parameter number in definition of \reserved@b.
如何处理 expl3 中的此类动态函数定义?
答案1
主要问题是参数文本不能用括号括起来。您可以使用“无参数”语法跳过它。请参阅https://tex.stackexchange.com/search?q=cs_set%3ANV使用示例
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\tl_set:Nn \l_tmpa_tl { \textbf{#1} }
\exp_args:NNV \cs_new:Nn \foo:n \l_tmpa_tl
\cs_set_eq:NN \foo \foo:n
\cs_show:N \foo
控制台上的输出是
> \foo=\long macro:#1->\textbf {#1}.
您也可以使用参数,但它真的很丑陋:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\exp_args_generate:n { NNNV }
\tl_set:Nn \l_tmpa_tl { \textbf{#1} }
\tl_set:Nn \l_tmpb_tl { #1 }
\exp_args:NNNNV
\exp_last_unbraced:NNV
\cs_new:Npn \foo \l_tmpb_tl \l_tmpa_tl
\cs_show:N \foo
答案2
有一个p
参数类型,它是 TeX 参数的包装器#{
。优点是宏的参数文本中有效的任何内容在这里都是有效的,而无需更改代码。缺点是后面的参数必须是用大括号括起来的,因此您要么需要将扩展类型从 更改为V
(o
由于实现细节,这将起作用),要么将用大括号括起来的单标记参数传递给V
(由于另一个实现细节,这将起作用)。
为了遵守expl3
语法并使用所需的括号,p
您可以使用v
:
\documentclass{article}
\usepackage{expl3}
\ExplSyntaxOn
\exp_args_generate:n { Npv } % p = #{
%
\tl_set:Nn \l_tmpa_tl { \textbf{#1} }
\exp_args:NNpv \cs_set:Npn \foo #1 { l_tmpa_tl }
% \foo=\long macro:#1->\textbf {#1}.
\exp_args:NNpv \cs_set:Npn \bold text #1 { l_tmpa_tl }
% \bold=\long macro:text#1->\textbf {#1}.
\ExplSyntaxOff
\begin{document}
\foo{hello} \bold text{world}
\end{document}