使用 csname 构建宏

使用 csname 构建宏

如何csname正确扩展?在下面的 MWE 中,我尝试制作一个将\prefixator和“绑定”在一起的宏\afterator。我希望\giveme{im}等同于\givemeim

\documentclass{article}                        
\usepackage[utf8]{inputenc}                    
\usepackage[T1]{fontenc}                       

\makeatletter                                  
\def\halo@re{Re}                               
\def\halo@im#1{Im}                             
\def\prefixator{halo@}                         

\newcommand{\giveme}{                          
    \edef\vv{\csname\prefixator\afterator\endcsname}
    \meaning\vv                                
}                                              

\newcommand{\givemeim}{                        
    \let\vv\halo@im                            
    \meaning\vv                                
}                                              
\makeatother                                   

\begin{document}                               
\def\afterator{im} %\def\afterator{re} works as expected                                 
\giveme                                        

\end{document}                                                                           

我知道\edef这行不通,因为它试图扩展\halo@im但没有参数。我尝试了所有方法,\let但没有成功\giveme{re}

编辑:实际问题当\SetEnumitemKey{sth}{unknownlabel=\arabic{enumi}}使用时会创建具有\enitkv@enumitem@sth以下含义的宏:\enitkv@setkeys{enumitem}{unknownlabel=\arabic{enumi}}。在这种情况下prefixator\enitkv@enumitem@,并且afteratorsth。(上下文是邪恶的)

(有缺陷)MWE:

\documentclass{article}                              
\usepackage[utf8]{inputenc}                          
\usepackage[T1]{fontenc}                             
\usepackage{enumitem}                                
\makeatletter                                        

\SetEnumitemKey{sth}{unknownlabel=\arabic{enumi}}    

% -- can't touch these                               
\def\prefixator{enitkv@enumitem@}                    
\def\afterator{sth}                                  
% --                                                 

\newcommand{\giveme}{                                
    % make a macro \vv \enitkv@enumitem@sth (bind them)
    % \let\vv\enitkv@enumitem@sth  
    \edef\vv{\csname\prefixator\afterator\endcsname{}} 
    \meaning\vv                                      
}                                                    
\makeatother                                        

\begin{document}                                     
\giveme                                                                                                   
\end{document}                                                                                

答案1

你的\csname...\endcsname是正确的。你忽略的是,\edef无论回报如何,它都会不断扩大\csname\prefixator\afterator\endcsname,并且是代码失败的时候。

经过一步扩展后,\csname\prefixator\afterator\endcsname变成\halo@im,然后剩下\edef\vv{\halo@im}。再进行一次扩展,您会收到错误消息:

! Argument of \halo@im has an extra }.
<inserted text>
                \par
l.24 \giveme

?

这说明 TeX 尝试获取的参数时\halo@im发现的}太早,从而导致了问题。您需要执行以下任一操作:A)从定义中删除参数\halo@imIE, \def\halo@im{Im},就像你做的那样\halo@re),或者b)\halo@im,在 中添加一个正式参数\edef\edef\vv{\csname\prefixator\afterator\endcsname{}}。第一个选项更有意义,因为您没有#1使用\halo@im

但是如果您只是想要一个不同名称的命令的副本,您可以执行以下操作:

\expandafter\let\expandafter\NewName\csname<command name>\endcsname

第一步扩展步骤是扩展第一个\expandafter,然后跳过\let并扩展第二个\expandafter,而第二个又会跳过\NewName并扩展\csname(扩展 X,跳过 S):

% X           S   X           S       X
 \expandafter\let\expandafter\NewName\csname<command name>\endcsname

一旦扩展\csname结束,您将得到:

\let\NewName\<command name>

它可以满足您的要求。

相关内容