定义命令,带或不带 \csname

定义命令,带或不带 \csname

我正在尝试做同样的事情这个\def,而是用\gdef\xdef代替。

另一个问题的简要总结:
我想打印命令(而不是命令的内容),无论它是否被定义\csname。解决方案是检查第一个字符串是否是\csname命令。

因此\def需要一个\expandafterif 与 一起使用\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}

按要求。

解决方案

我们必须去掉\fibefore\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来表示分别返回真或假的任何条件构造;XY表示任何标记列表。

答案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标记来跟踪其使用情况。这就是为什么如果您稍后尝试使用定义的标记,则会收到错误。

相关内容