我有一个命令,它接受逗号分隔的列表并对其进行处理。我想使用expl3
属性列表存储一组这样的列表。这是问题的简单版本。我的基本命令可以工作,但是当我尝试使用从属性列表中检索到的列表时,它会挂起,我不明白为什么。(取消注释命令\mylist
中的调用\fromprop
以查看问题。
\documentclass{article}
\ExplSyntaxOn
\clist_new:N \l_mylist_clist
\NewDocumentCommand{\mylist}{m}{
\clist_set:Nn \l_mylist_clist {#1}
\int_step_inline:nn {4}{
\clist_pop:NN \l_mylist_clist \l_tmpa_tl
\l_tmpa_tl\par
}}
\prop_new:N \l_myprop_prop
\prop_set_from_keyval:Nn \l_myprop_prop {
A = {1,2,3,4},
B = {1,1,2,2},
C = {1,1,1,1}
}
\NewDocumentCommand{\fromprop}{m}{
\prop_get:NnN \l_myprop_prop {#1} \l_tmpb_tl
\l_tmpb_tl
% \mylist{\l_tmpb_tl}
}
\ExplSyntaxOff
\begin{document}
\mylist{1,2,3,4}
\fromprop{A}
\end{document}
答案1
您要尝试将其涂抹\mylist
到瓶子上,而不是涂抹到里面的酒上。
使用代码的复杂命令expl3
应该在“用户级别”和“程序员级别”之间划分。
因此,您可以生成适合程序员级别函数的变体。
\documentclass{article}
\ExplSyntaxOn
\clist_new:N \l_mylist_clist
\prop_new:N \l_myprop_prop
\prop_set_from_keyval:Nn \l_myprop_prop {
A = {1,2,3,4},
B = {1,1,2,2},
C = {1,1,1,1}
}
\NewDocumentCommand{\mylist}{m}
{
\alan_mylist:n { #1 }
}
\cs_new_protected:Nn \alan_mylist:n
{
\clist_set:Nn \l_mylist_clist {#1}
\int_step_inline:nn {4}
{
\clist_pop:NN \l_mylist_clist \l_tmpa_tl
\l_tmpa_tl\par
}
}
\cs_generate_variant:Nn \alan_mylist:n { V }
\NewDocumentCommand{\fromprop}{m}
{
\prop_get:NnN \l_myprop_prop {#1} \l_tmpb_tl
\alan_mylist:V \l_tmpb_tl
}
\ExplSyntaxOff
\begin{document}
\mylist{1,2,3,4}
\fromprop{A}
\end{document}
答案2
您可以看到此测试文档中存在的问题:
\documentclass{article}
\ExplSyntaxOn
\clist_new:N \l_mylist_clist
\NewDocumentCommand{\mylist}{m}{
\clist_set:Nn \l_mylist_clist {#1}
\show \l_mylist_clist % <---- HERE
\int_step_inline:nn {4}{
\clist_pop:NN \l_mylist_clist \l_tmpa_tl
\show \l_tmpa_tl % <---- HERE
\l_tmpa_tl\par
}}
\prop_new:N \l_myprop_prop
\prop_set_from_keyval:Nn \l_myprop_prop {
A = {1,2,3,4},
B = {1,1,2,2},
C = {1,1,1,1}
}
\NewDocumentCommand{\fromprop}{m}{
\prop_get:NnN \l_myprop_prop {#1} \l_tmpb_tl
\l_tmpb_tl
\mylist{\l_tmpb_tl}
}
\ExplSyntaxOff
\begin{document}
\mylist{1,2,3,4}
\fromprop{A}
\end{document}
输出结果如下:
> \l_mylist_clist=macro:
->1,2,3,4.
> \l_tmpa_tl=macro:
->1.
[...]
> \l_mylist_clist=macro:
->\l_tmpb_tl .
> \l_tmpa_tl=macro:
->\l_tmpb_tl .
> \l_tmpa_tl=macro:
->\q_no_value .
这里的问题是,你将 a 设置clist
为包含 的单个元素\l_tmpb_tl
。如果你弹出 1 个元素clist
4 次,你最终会得到一个空值,在 expl3 中由 quark 表示\q_no_value
。然后,你排版这个 quark,它会尝试扩展它,导致无限循环。来自文档:
Quark 是控制序列(实际上是标记列表),它们会自行扩展,因此永远不应在代码中直接执行。这会导致无限循环!
为了修复这个问题,我建议这样做:
\documentclass{article}
\ExplSyntaxOn
\cs_new_protected:Nn \mylist_helper:n {
\clist_map_inline:nn { #1 } {
##1\par
}
}
\cs_set_eq:NN \mylist \mylist_helper:n
\cs_generate_variant:Nn \mylist_helper:n { V }
\prop_new:N \l_myprop_prop
\prop_set_from_keyval:Nn \l_myprop_prop {
A = {1,2,3,4},
B = {1,1,2,2},
C = {1,1,1,1}
}
\NewDocumentCommand{\fromprop}{m}{
\prop_get:NnN \l_myprop_prop {#1} \l_tmpb_tl
\l_tmpb_tl
\mylist_helper:V \l_tmpb_tl
}
\ExplSyntaxOff
\begin{document}
\mylist{1,2,3,4}
\fromprop{A}
\end{document}
在这里,我们正确地扩展了中的变量,并且通过使用内置迭代器\fromprop
避免意外超出的末尾。clist
编辑
谢谢,但这并没有捕捉到我需要保留的代码的一个基本属性,特别是宏
\mylist
本身,它(出于与此无关的原因)不能仅通过简单的映射函数来实现。那么有没有一种解决方案可以保持\mylist
完整并满足我的要求?
因此,我正在寻找一种方法,使输出的行为
\fromprop
与我直接输入列表的行为完全一样。
一个最小改变的解决方案:
\documentclass{article}
\ExplSyntaxOn
\clist_new:N \l_mylist_clist
\NewDocumentCommand{\mylist}{m}{
\clist_set:Nn \l_mylist_clist {#1}
\int_step_inline:nn {4}{
\clist_pop:NN \l_mylist_clist \l_tmpa_tl
\quark_if_no_value:NF \l_tmpa_tl { % <--- CHANGED
\l_tmpa_tl\par
}
}}
\prop_new:N \l_myprop_prop
\prop_set_from_keyval:Nn \l_myprop_prop {
A = {1,2,3,4},
B = {1,1,2,2},
C = {1,1,1,1}
}
\NewDocumentCommand{\fromprop}{m}{
\prop_get:NnN \l_myprop_prop {#1} \l_tmpb_tl
\l_tmpb_tl
\exp_args:NV \mylist \l_tmpb_tl % <--- CHANGED
}
\ExplSyntaxOff
\begin{document}
\mylist{1,2,3,4}
\fromprop{A}
\end{document}
此解决方案用于在 之前\exp_args:NV
扩展 的值。它还用于防止在到达列表末尾时意外扩展 quark(这部分不是绝对必要的,但这可能是一个好主意)。\l_tmpb_tl
\mylist
\quark_if_no_value:NF