我正在尝试做同样的事情这个\def
,而是用\gdef
或\xdef
代替。
另一个问题的简要总结:
我想打印命令(而不是命令的内容),无论它是否被定义\csname
。解决方案是检查第一个字符串是否是\csname
命令。
因此\def
需要一个\expandafter
if 与 一起使用\csname
。如果没有,则一切正常:
\def\str{String}
\expandafter\def\csname str\endcsname{String}
两者都是正确的。但如果我想用参数()来更改\str
或。现在不知道我是否需要使用。如果在不需要时使用,则会导致错误。我写了这个(与另一个问题类似)\csname str\endcsname
#1
\expandafter
\def\defcmd#1{
\ifx\csname#1
\expandafter\def\csname
\else
\def#1
\fi
}
\defcmd\str{String}
\defcmd\csname str\endcsname{String}
\defcmd
这将吸收参数 ( )之后的第一个字符串#1
,检查它是否为\csname
或其他内容,然后用 或 替换自身\expandafter\def
并将\def
参数放回原处。
运行该代码时,完全没有问题。但是当我尝试输出命令(直接或在文件中)时,我收到以下错误:
! Use of \str doesn't match its definition
l.24
我不知道为什么会这样。(l.24 是使用后的一行\str
)
答案1
让我们看看这两种情况下发生了什么。
\defcmd\str{foo}
这变成
\ifx\csname\str\expandafter\def\csname\else\def\str\fi
并且测试结果为假,因此输入流中剩余的是
\def\str\fi{foo}
这对于 TeX 来说是完全可以接受的,但是有两个问题:\str
必须随后\fi
会出现一个关于忘记\fi
\defcmd\csname str\endcsname{foo}
这变成
\ifx\csname\csname\expandafter\def\csname\else\def\csname\fi str\endcsname{foo}
TeX 将会留在输入流中
\expandafter\def\csname\else\def\csname\fi str\endcsname{foo}
现在\expandafter
展开\csname
,这将消除\else
和之间的内容\fi
,从而得到
\def\str{foo}
按要求。
解决方案
我们必须去掉\fi
before\def
被执行。David 已经展示了一种方法。或者:
\makeatletter
\def\defcmd#1{%
\ifx\csname#1%
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
{\expandafter\def\csname}{\def#1}%
}
\makeatother
\def\str{foo}
我们有
\ifx\csname\str
这是错误的,所以剩下的是
\expandafter\@secondoftwo\fi{\expandafter\def\csname}{\def\str}{foo}
变成(的展开\fi
为空)
\@secondoftwo{\expandafter\def\csname}{\def\str}{foo}
最后
\def\str{foo}
如果\defcmd\csname str\endcsname{foo}
我们有
\ifx\csname\csname\expandafter\@firstoftwo
\else\expandafter\@secondoftwo\fi
{\expandafter\def\csname}{\def\csname}str\endcsname{foo}
并且由于测试结果正确,
\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{\expandafter\def\csname}{\def\csname}str\endcsname{foo}
的扩展\else
为空,并删除了匹配之前的所有内容\fi
,因此我们剩下
\@firstoftwo{\expandafter\def\csname}{\def\csname}str\endcsname{foo}
最后
\expandafter\def\csname str\endcsname{foo}
这正是我们所需要的。
当条件为真或假时,条件中的“跳过标记”执行方式不同:\iftrue X\else Y\fi
离开X\else Y\fi
并且 的扩展会\else
去掉Y
;相反,\iffalse X\else Y\fi
将离开Y\fi
,跳过直到 的标记(包括 )\else
。 的扩展\fi
为空,但直到它不被扩展之前,它都会保留在输入流中。
这里我使用\iftrue
和\iffalse
来表示分别返回真或假的任何条件构造;X
和Y
表示任何标记列表。
答案2
\def\defcmd#1{%
\ifx\csname#1%
\expandafter\expandafter\expandafter\def\expandafter\csname
\else
\expandafter\def\expandafter#1%
\fi
}
\defcmd\str{String}
\show\str
\defcmd\csname str\endcsname{String2}
\show\str
\bye
两个典型的错误:忘记吃饱\expandafter
和忘记%
排队:-)
如果你用原来的定义替换它,则会\show
显示
tex foo
This is TeX, Version 3.1415926 (TeX Live 2012)
(./foo.tex
> \str=macro:
\fi ->String.
l.23 \show\str
?
> \str=macro:
->String2.
l.28 \show\str
因此,第二次调用实际上按预期工作,但第一次调用的定义\str
就像你已经做了一样
\def\str\fi{....}
并且它需要一个\fi
标记来跟踪其使用情况。这就是为什么如果您稍后尝试使用定义的标记,则会收到错误。