Latex3:将变量转发到组外的优雅方法

Latex3:将变量转发到组外的优雅方法

我想在 LaTeX3 中的组中定义一个宏,以便它在组之后保持定义,但不使用全局变量。现在我这样做:

\documentclass{article}
\ExplSyntaxOn
\NewDocumentEnvironment{test}{}{}{
  \str_clear_new:N \mytest
  \str_put_right:Nx \mytest {I ~ like ~}
  \str_gset_eq:NN \dummyvar \mytest
  \group_insert_after:N \str_set_eq:NN
  \group_insert_after:N \mytest
  \group_insert_after:N \dummyvar
}
\ExplSyntaxOff
\begin{document}
\def\mytest{chocolate.}
{
  \begin{test}
    I’d like mytest to be defined at the end of the group without using global variables.
  \end{test}
  \mytest
}
\mytest
\end{document}

它可以工作,但是看起来真的很脏,比如我需要引入一个全局虚拟变量等等...我尝试这样做:

  \group_insert_after:N \str_set_eq:NN
  \group_insert_after:N \mytest
  \expandafter \group_insert_after:N \mytest

但有趣的是,这个字符串现在是倒着写的!!我也试图生成一个变体,\group_insert_after:V但这是被禁止的。

答案1

我理解,\dummyvar如果你想在组后保留多个宏的含义,那么这种方法行不通。但你可以设置一个从给定控制序列的名称派生的控制序列:

\def\keepaftergroup#1{%
   \global \expandafter\let \csname x:\string#1\endcsname =#1
   \aftergroup\let
   \aftergroup#1%
   \expandafter\aftergroup \csname x:\string#1\endcsname
   
}

\def\mytest{nazdar}

{
   \def\mytest{Hello}
   \def\mysecond{Hi}
   \keepaftergroup\mytest
   \keepaftergroup\mysecond
   Text in group.%
}
After group: \mytest, \mysecond

答案2

我们目前没有“脱离任意组级别”功能,主要是因为这是一个不寻常的要求。另一方面,如果你想在你控制的组之外设置变量,这很简单

\group_begin:
   % Stuff happens
   \str_set:Nn \l__mypkg_str { ... }
\exp_args:NNNV \group_end:
\str_set:Nn \l__mypkg_str \l__mypkg_str

等等。

答案3

下面定义了一种使用单个辅助全局令牌将物品走私到上一级的机制。

它不适用于toks寄存器。我希望我没有搞砸实现的其他方面。

\documentclass{article}
\ExplSyntaxOn
\tl_new:N \g__tobiasbora_smuggler_tl
\cs_new:Npn \tobiasbora_smuggle:n #1
  {
    \tl_gset:Nx \g__tobiasbora_smuggler_tl
      {
        \tl_map_function:nN {#1} \__tobiasbora_smuggle:N
        \exp_not:n { \tl_gset:Nn \g__tobiasbora_smuggler_tl }
          { \exp_not:o \g__tobiasbora_smuggler_tl }
      }
    \group_insert_after:N \g__tobiasbora_smuggler_tl
  }
\cs_new:Npn \__tobiasbora_smuggle:N #1
  {
    \token_if_macro:NTF #1
      {
        \exp_not:n { \cs_set:Npx #1 }
          { \exp_not:N \exp_not:n { \exp_not:o #1 } }
      }
      {
        \token_if_chardef:NTF #1
          { \exp_not:n { \chardef #1 } = \exp_not:V #1 \scan_stop: }
          {
            \token_if_mathchardef:NTF #1
              { \exp_not:n { \mathchardef #1 } = \exp_not:V #1 \scan_stop: }
              {
                % assume it's a register type and the following is fine
                #1 = \exp_not:V #1 \scan_stop:
              }
          }
      }
  }
\NewDocumentEnvironment{test}{}{}{
  \str_set:Nn \mytest { like~ }
  \tobiasbora_smuggle:n { \mytest \mycount }
}
\ExplSyntaxOff

\newcount\mycount
\mycount=0

\begin{document}
\def\mytest{chocolate.}
{
  \begin{test}
    I’d like mytest to be defined at the end of the group without using global variables.
    \mycount=1
  \end{test}%
  \uppercase\expandafter{\romannumeral\mycount} % this prints "I"
  \mytest
}%
\mytest
\romannumeral\mycount % this prints nothing as it's 0 again
\end{document}

相关内容