以下代码打印 ==atname==
\def\atname{atname}
\def\xxx{name}
\def\at{at}
==\csname\at\xxx\endcsname==
\bye
但事实并非如此:
\def\@name{atname}
\def\xxx{name}
\def\at{@}
==\csname\at\xxx\endcsname==
\bye
为什么?我怎样才能实现这一点?
答案1
\def\@name{atname}
未定义\@name
,但\@
带有参数 text name
。同样在纯 TeX 中, 的默认 catcode 为@
12。
\catcode`\@=11
\def\@name{atname}
\def\xxx{name}
\def\at{@}
==\csname\at\xxx\endcsname==
\bye
答案2
控制序列定义由三部分组成:
- 控制序列名称;
- 参数文本;
- 替换文本。
这参数文本是控制序列名称和界定替换文本的左括号{
1之间的任何内容。它能包含参数标记#1
... #9
,还包括其他标记。
控制序列可以由一个或多个字母的序列组成(在这种情况下,字母是类别代码为 11 的字符),也可以由单身的非字母(任何类别代码)。
但是,控制序列名称可以通过扩展来形成:将使用\csname
由标记的完整扩展直至匹配所产生的所有字符标记,而与它们的类别代码无关。\endcsname
在正常设置下,@
类别代码为 12,因此
\def\@name{atname}
定义\@
,因为单个非字母会结束对控制序列名称的扫描。参数文本是标记列表name
,它是必需的\@
在使用时遵循。
所以你可以通过以下方式
\catcode`@=11 % make @ a letter
\def\@name{atname}
\catcode`@=12 % go back to the default
\def\xxx{name}
\def\at{@}
==\csname\at\xxx\endcsname==
\bye
或者
\expandafter\def\csname @name\endcsname{atname}
\def\xxx{name}
\def\at{@}
==\csname\at\xxx\endcsname==
\bye
因为\expandafter
控制序列名称由扩展组成\csname
前 \def
完成其工作。