将宏的未知内容存储在列表中

将宏的未知内容存储在列表中

[根据 egreg 的回答编辑] 我想将宏及其内容成对存储macro {macro contents}在 clist 中。宏将在其他地方定义,由用户或在另一个包中定义,并将包含数字或数学公式。问题是,仅给定宏名称,例如\mymacro,我如何查看存储在中的内容\mymacro?在以下示例中,\exp_not:f当宏定义包含前导空格时成功,但当不包含前导空格时失败。

\documentclass{article}
%\usepackage{amsmath}

% space before \sin
\NewDocumentCommand \myloosemacro {} { \sin(\pi/6) }
% no space before \sin
\NewDocumentCommand \mytightmacro {} {\sin(\pi/6)}

\begin{document}
\ExplSyntaxOn

\cs_new_protected:Npn \__storemacros:N #1
  { \clist_put_right:Nx \l_tmpa_clist { #1 { \exp_not:f #1 } } }
  
\clist_clear:N \l_tmpa_clist

\__storemacros:N \myloosemacro
\__storemacros:N \mytightmacro

\clist_show:N \l_tmpa_clist

\ExplSyntaxOff
\end{document}

这表明\l_tmpa_clist包含对:

\myloosemacro {\sin (\pi /6) }
\mytightmacro {\protect \sin  (\pi /6)}

第一个是期望的结果,第二个包含一个额外的不需要的标记——宏定义中不存在。通过取消注释\usepackage{amsmath},情况变得更糟。第二个\mytightmacro {\protect \qopname \relax o{sin}(\pi /6)}包含许多在定义时不存在的额外标记。如前所述,宏将来自其他包或用户输入,因此我无法控制初始空格的存在与否。

答案1

您使用了错误的工具。

使用\NewDocumentCommand{\foo}{}{<code>},您正在定义一个\protected宏,它将在x- 或e-expansion 中保持不变。但是,\protected在 -expansion 中不起作用f

如果你这样做\show\myloosemacro,你会看到宏定义为

> \myloosemacro=\protected macro:
->\__cmd_start_expandable:nNNNNn {}\myloosemacro  \myloosemacro  \myloosemacro code ?{}.

替换文本存储在\myloosemacro code(是的,名称中有一个空格)

? i\expandafter\show\csname myloosemacro code\endcsname
> \myloosemacro code=\protected\long macro:
-> \sin (\pi /6) .

如果我对它做同样的事情\mytightmacro,我会看到

? i\expandafter\show\csname mytightmacro code\endcsname
> \mytightmacro code=\protected\long macro:
->\sin (\pi /6).

这里您可以看到前者的初始空间。

您应用 进行\exp_not:f递归一级扩展,在发现不可扩展标记时停止(如果是空格则忽略它)。 定义中的标记\myloosemacro旨在在f-扩展中不产生任何内容,直到到达\myloosemacro code ?{},这只会产生替换文本。这里是空间被吞噬的地方,因为它停止了f-扩展。

本质上, 也发生了相同的事情\mytightmacro,但有一个重要的区别:没有空格阻止f-扩展,因此\sin被扩展。 并\show\sin告诉你定义是

> \sin=macro:
->\protect \sin  .

(最后一个命令的名称后面有一个空格)。您很幸运,因为在调用时,\protect\relax,因此它会阻止f-expansion(但不会被忽略)。

\documentclass{article}
%\usepackage{amsmath}

\ExplSyntaxOn
\NewDocumentCommand{\definevar}{mm}
 {
  \tl_new:N #1
  \tl_set:Nn #1 { #2 }
 }
\ExplSyntaxOff
% space before \sin
\definevar \myloosemacro { \sin(\pi/6) }
% no space before \sin
\definevar \mytightmacro {\sin(\pi/6)}

\begin{document}

\ExplSyntaxOn

\cs_generate_variant:Nn \tl_trim_spaces:n { e }

\cs_new_protected:Npn \__storemacros:N #1
  { \clist_put_right:Nx \l_tmpa_clist { \exp_not:N #1 { \tl_trim_spaces:e { \exp_not:V #1 } } } }
  
\clist_clear:N \l_tmpa_clist

\__storemacros:N \myloosemacro
\__storemacros:N \mytightmacro

\clist_show:N \l_tmpa_clist

\ExplSyntaxOff
\end{document}

将会呈现

The comma list \l_tmpa_clist contains the items (without outer braces):
>  {\myloosemacro {\sin (\pi /6)}}
>  {\mytightmacro {\sin (\pi /6)}}.

答案2

The comma list \l_tmpa_clist contains the items (without outer braces):
>  {\myloosemacro { \sin (\pi /6) }}
>  {\mytightmacro {\sin (\pi /6)}}
>  {\myoldmacro {\frac {1}{2}}}.

产自

\documentclass{article}
%\usepackage{amsmath}

% space before \sin
\NewDocumentCommand \myloosemacro {} { \sin(\pi/6) }
% no space before \sin
\NewDocumentCommand \mytightmacro {} {\sin(\pi/6)}

\newcommand\myoldmacro{\frac{1}{2}}

\begin{document}
\ExplSyntaxOn

\cs_new_protected:Npn \__storemacros:N #1
  {
\ifcsname \exp_after:wN \use_none:n\token_to_str:N#1~ code\endcsname
\exp_after:wN\exp_after:wN\exp_after:wN
 \clist_put_right:Nn
\exp_after:wN\exp_after:wN\exp_after:wN
        \l_tmpa_clist
\exp_after:wN\exp_after:wN\exp_after:wN {
\exp_after:wN\exp_after:wN\exp_after:wN
            #1
\exp_after:wN\exp_after:wN \exp_after:wN 
{ \csname \exp_after:wN \use_none:n\token_to_str:N#1~ code\endcsname } } 
\else
\exp_after:wN \clist_put_right:Nn \exp_after:wN
        \l_tmpa_clist \exp_after:wN { \exp_after:wN
            #1 \exp_after:wN { #1 } } 
\fi}
  
\clist_clear:N \l_tmpa_clist

\__storemacros:N \myloosemacro
\__storemacros:N \mytightmacro
\__storemacros:N \myoldmacro

\clist_show:N \l_tmpa_clist

\ExplSyntaxOff
\end{document}

相关内容