谁吃了我的空间?(如何阻止 \exp_args:Nf 占用空间?)

谁吃了我的空间?(如何阻止 \exp_args:Nf 占用空间?)

我有一个宏,它用来\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,我复制了它的底层实现;-)

相关内容