我正在尝试从我自己使用的代码中删除软件包pgffor
和的依赖项,但我不知道哪个是中的正确等价物。目前我有以下代码,它可以工作,但我不知道这是否是替换它的正确方法。etoolbox
expl3
\csxdef
expl3
\documentclass{article}
\usepackage{xparse}
\usepackage{etoolbox}
\usepackage{pgffor}
\ExplSyntaxOn
\NewDocumentCommand{\mycmdone}{ m m }
{
\_csxdef_pgfetoolbox:nn { #1 } { #2 }
}
\cs_new_protected_nopar:Npn \_csxdef_pgfetoolbox:nn #1 #2
{
\foreach \x [count=\n] in { #2 } { \csxdef{#1\n}{\x} } % save in \#1<n>
}
\NewDocumentCommand{\mycmdtwo}{ m m }
{
\_csxdef_expl:nn { #1 } { #2 }
}
\cs_new_protected_nopar:Npn \_csxdef_expl:nn #1 #2
{
\clist_set:Nn \l_tmpa_clist {#2}
\int_step_inline:nn { \clist_count:N \l_tmpa_clist }
{
\cs_set:cpx {l_#1##1:} { \clist_item:Nn \l_tmpa_clist { ##1 } }
}
}
\ExplSyntaxOff
\begin{document}
Test mycmdone
\mycmdone{A}{X,Y,Z,W}
\csuse{A1} \csuse{A2} \csuse{A3} \csuse{A4}
% repeat
\mycmdone{A}{X,Y,Z,W}
\csuse{A1} \csuse{A2} \csuse{A3} \csuse{A4}
\par
Test mycmdtwo
\mycmdtwo{B}{P,Q,R}
\ExplSyntaxOn
\use:c{l_B1:} ~ \use:c{l_B2:} ~ \use:c{l_B3:}
\ExplSyntaxOff
% repeat
Test mycmdtwo
\mycmdtwo{B}{P,Q,R}
\ExplSyntaxOn
\use:c{l_B1:} ~ \use:c{l_B2:} ~ \use:c{l_B3:}
\ExplSyntaxOff
\end{document}
命令接受两个参数,其中第二个参数用逗号分隔,不直接在文档中使用,而是\csuse
作为参数传递给我定义的另一个代码。我不知道我应该使用什么\cs_new:
,或者\l_#1#2_tl
是否expl3
有一个已经执行此操作的函数(我不想重新发明轮子)。
问候。
答案1
这更像是一条对于评论来说太长的评论......
因为看起来您希望能够重新定义这些命令,所以我认为您需要使用\cs_set:cpx
(或\cs_gset:cpx
或\cs_set:cx
或\cs_set:cx
),但这里不需要两个函数,而是以下内容就足够了:
\documentclass{article}
\usepackage{xparse}
\usepackage{etoolbox}
\usepackage{pgffor}
\ExplSyntaxOn
\NewDocumentCommand{\mycmdtwo}{ m m }
{
\clist_set:Nn \l_tmpa_clist {#2}
\int_step_inline:nn {\clist_count:N \l_tmpa_clist}
{
\cs_set:cpx {l_#1##1:} { \clist_item:Nn \l_tmpa_clist {##1} }
}
}
\NewDocumentCommand\mycmd{m}{\use:c{l_#1:}}
\ExplSyntaxOff
\begin{document}
Test mycmdtwo
\mycmdtwo{B}{P,Q,R}
\mycmd{B1} \mycmd{B2} \mycmd{B3}
% repeat
Test mycmdtwo
\mycmdtwo{B}{P,Q,R}
\mycmd{B1} \mycmd{B2} \mycmd{B3}
\end{document}
我还给出了“帮助”命令\mycmd
。
您也可以使用\cs_set:cx
或\cs_gset:cx
但是,正如约瑟夫在评论中指出的那样,\cs_set:cpx
而且\cs_gset:cpx
速度要快得多。
答案2
我会做一点不同的事情。您所放置的代码会遍历逗号列表2+<num>
次,其中<num>
是列表中的项目数。第一次迭代是在\clist_set:Nn
,它循环修剪空格。第二次迭代是在\clist_count:N
,它再次循环以计算项目数。并且迭代次数与列表中的项目数一样多\clist_item:Nn
,它不会直接跳到您想要的项目,而是扫描每个项目直到找到您想要的项目。这不是最理想的。事实上,用来l3benchmark
衡量性能,您的代码的 10 万次迭代运行在 1.32 秒内,而下面的代码运行在 0.39 秒内,速度提高了 3 倍多。
我建议使用\clist_map_inline:nn
(或类似的东西),它将只在列表中迭代一次,并使用辅助计数器来跟踪项目编号。
我认为您应该<tl var>
在这里使用 和\tl_new:c
而\tl_set:cx
不是\cs_set:cx
(顺便说一句,它比 慢得多\cs_set:cpx
)。而且,由于生成的项不是函数(expl3
术语上),而是变量,因此这种替代方法似乎更好。然后可以将访问器函数更改为\tl_use:c
,它将检查请求的变量是否存在并在适当时发出错误。\use:c
不希望在这里使用,因为如果请求的变量不存在,它将扩展为\relax
并且不会引发错误。
最后,如果您计划重复使用已创建的标记列表,那么您可以使用清除变量或创建变量(取决于\tl_new:c
变量是否存在)来代替(如果变量存在则会引发错误) 。\tl_clear_new:c
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\int_new:N \l_pablo_tmp_int
\NewDocumentCommand{\mycmdtwo}{ m m }
{
\int_zero:N \l_pablo_tmp_int
\clist_map_inline:nn {#2}
{
\int_incr:N \l_pablo_tmp_int
\tl_clear_new:c { l_pablo_#1 \int_use:N \l_pablo_tmp_int _tl } % Redundant here, but good practice in general
\tl_set:cx { l_pablo_#1 \int_use:N \l_pablo_tmp_int _tl } {##1}
}
}
\NewDocumentCommand\mycmd {m} { \tl_use:c { l_pablo_#1_tl } }
\ExplSyntaxOff
\begin{document}
Test mycmdtwo
\mycmdtwo{B}{P,Q,R}
\mycmd{B1} \mycmd{B2} \mycmd{B3}
% repeat
Test mycmdtwo
\mycmdtwo{B}{P,Q,R}
\mycmd{B1} \mycmd{B2} \mycmd{B3}
\end{document}
TeXhackers 注释: \tl_set:cx
做\cs_set_nopar:cpx
(IE, \expandafter\xdef\csname...\endcsname
,所以\tl_new:c
是多余的。但最佳实践是先声明变量再使用它。
答案3
标记列表变量与函数不同。您的代码旨在存储标记列表,而不是定义操作。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\mycmd}{mm}
{
\seq_set_from_clist:Nn \l__pablo_mycmd_seq { #2 }
\seq_indexed_map_inline:Nn \l__pablo_mycmd_seq
{
\tl_clear_new:c { l_pablo_#1##1_tl }
\tl_set:cn { l_pablo_#1##1_tl } { ##2 }
}
}
\NewExpandableDocumentCommand{\pablouse}{m}
{
\tl_use:c { l_pablo_#1_tl }
}
\ExplSyntaxOff
\begin{document}
Test mycmd
\mycmd{A}{X,Y,Z,W}
\pablouse{A1} \pablouse{A2} \pablouse{A3} \pablouse{A4}
\end{document}
我的解决方案与 Phelype Oleynik 的收益的比较基准
8.22e-5 seconds (252 ops)
1.08e-4 seconds (321 ops)
上面是我的解决方案,下面是 Phelype 的。