[根据 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}