我有一个宏,它用来\prg_replicate:nn
生成多个空格,然后在 f 扩展后将这些空格传递\prg_replicate:nn
给另一个宏。问题是,当我使用时\exp_args:Nf
,它将使用\romannumeral 0
可以消耗空格的东西。猜猜怎么着,这个空间从我的复制空间中被删除了,所以在整个事情完成后,我的空间就少了一个。
此问题通过以下 MWE 重现:
\documentclass{article}
\usepackage{expl3}
\begin{document}
\ExplSyntaxOn
\cs_new:Npn \__printf_pre_output:n #1 { [ \tl_to_str:n {#1} ] }
\cs_set:Npn \__printf_tmp:w #1
{
\cs_new:Npn \__printf_format_final_print:n ##1
{
\exp_args:Nf \__printf_pre_output:n
{ \prg_replicate:nn {##1} {#1} }
}
}
\__printf_tmp:w { ~ }
\ttfamily
Wrong,~4~spaces:~\__printf_format_final_print:n {5}\par
Right,~5~spaces:~[\ \ \ \ \ ]\par
\ExplSyntaxOff
\end{document}
生成结果:
\romannumeral
除了显而易见的“首先用额外的空间做整个事情”之外,我找不到其他方法来阻止我占用我的一个空间。
目前,我正在使用额外的空间进行复制\romannumeral
,但这似乎是一种不成熟的做法。还有其他可能性吗?
答案1
我只需使用新的e
在这里简单地使用新类型的方法(IE使用\expanded
原始或等效的方法):
\documentclass{article}
\usepackage{expl3}
\begin{document}
\ExplSyntaxOn
\cs_new:Npn \__printf_pre_output:n #1 { [ \tl_to_str:n {#1} ] }
\cs_set:Npn \__printf_tmp:w #1
{
\cs_new:Npn \__printf_format_final_print:n ##1
{
\exp_args:Ne \__printf_pre_output:n
{ \prg_replicate:nn {##1} {#1} }
}
}
\__printf_tmp:w { ~ }
\ttfamily
Wrong,~4~spaces:~\__printf_format_final_print:n {5}\par
Right,~5~spaces:~[\ \ \ \ \ ]\par
\ExplSyntaxOff
\end{document}
这很可能成为此类情况的标准方法:f
既然我们可以使用原语e
直接使用 -type\expanded
或(必要时)模拟 -type,那么 -type 扩展就不那么重要了。请注意,MiKTeX 已经\expanded
在 pdfTeX 和 XeTeX 中实现了 -type,并且这将出现在 TeX Live 2019 中。还请注意,LuaTeX\expanded
从第一天起就拥有了。(模拟是可靠的,但确实会对性能产生影响:目前,对于需要在紧密循环或类似循环中工作的任何代码,最好避免使用它。)
答案2
就像 @jfbu 提到的那样,扩展两次就足够了\prg_replicate:nn
。因此,使用\exp_args:No
两次就足够了:
\documentclass{article}
\usepackage{expl3}
\begin{document}
\ExplSyntaxOn
\cs_new:Npn \__printf_pre_output:n #1 { [ \tl_to_str:n {#1} ] }
\cs_set:Npn \__printf_tmp:w #1
{
\cs_new:Npn \__printf_format_final_print:n ##1
{
\exp_args:NNo \exp_args:No \__printf_pre_output:n
{ \prg_replicate:nn {##1} {#1} }
}
}
\__printf_tmp:w { ~ }
\ttfamily
Wrong,~4~spaces:~\__printf_format_final_print:n {5}\par
Right,~5~spaces:~[\ \ \ \ \ ]\par
\ExplSyntaxOff
\end{document}
答案3
我只能赞同@JosephWright 和@Skillmon 的回答,但就我所知,xint
你只需要扩展一次\romannumeral\xintreplicate{100}{ }
就可以得到 100 个空格。所以如果在宏中
\def\x{\romannumeral\xintreplicate{100}{ }}
只需扩展\x
两次。
或者
\def\x{\xintreplicate{100}{ }}
那么你就可以这样做\romannumeral\x
。
哦,等等,我完全忘记了:\romannumeral\xintreplicate
基本上是(根据不同的用户界面)\prg_replicate:nn
,我复制了它的底层实现;-)
。