csname 方法的缺点是避免命令后出现空格

csname 方法的缺点是避免命令后出现空格

我遇到了与此类似的问题:LaTeX 命令后的空格

我的第一次尝试是这样的:

\newcommand{\satip}{SAT\textgreater IP}

这会导致已知问题,即命令后的空格被吃掉:

\satip is a cool Protocol. %Produces: SAT>IPis a cool Protocol.
                             space missing ^^^

我四处搜索,找到了提到的问题。提供的解决方案很有帮助,但我对其中任何一个都不完全满意。\satip/在乳胶文档中看起来有点奇怪,我\satip{}更喜欢。只是,如果我忘记在{}命令后面加上空格,输出中就会缺少空格。因此,如果我使用错误,我希望得到一个错误。

可能的解决方案:

\def\satip#{SAT\textgreater IP}
%\satip is a cool Protocol. %doesn't compile, error

这样,左括号就会被强制使用,但是括号中可以包含一些内容:

\satip{is} a cool Protocol.

这段代码编译得很好,但是由于没有任何意义,我希望它产生错误。我目前处理这个问题的方法是这样的:

\expandafter\def\csname satip{}\endcsname \relax{SAT\textgreater IP}
\def\satip#1{\csname satip{}\endcsname #1\relax}

%\satip{is} a cool Protocol. %Use of \satip{} doesn't match its definition.
%\satip is a cool Protocol. %Use of \satip{} doesn't match its definition.
\satip{} is a cool Protocol. %works

现在我的问题是:

此宏需要第二个扩展步骤。这会引起什么问题吗?还有其他问题吗?(因为我之前从未在任何地方发现过这个问题。)

附言:抱歉,标题不好,我还没想出更好的。欢迎随意修改。

答案1

您可以随时使用

\newcommand*\satip{SAT\textgreater IP}
\satip{} is a cool protocol

我没发现问题。


satip{}顺便说一下,你的最后一个定义用名称(括号)定义了宏包括在宏名称中)后面要跟一个\relax标记。如果将 放在宏中的和#1之间,则只有当为空时(即,只有给出空括号时)它才能工作。\endcsname\relax\satip#1\satip{} is...


这也许能达到你的要求?

\newcommand*\satip[1]
 {\if\relax\detokenize{#1}\relax
    SAT\textgreater IP%
  \else
    \GenericError{} % <- I don't know what this argument does
       {Wrong use of \string\satip{}.} % <- short version
       {Wrong use of \string\satip. You must use \string\satip\space followed by an empyt argument `{}'.}% <- long version
  \fi}

答案2

我不会{}以辅助宏的名称使用它,但该方法是合理的:

\newcommand{\satip}[1]{\csname satip\string+\endcsname #1\relax}
\expandafter\def\csname satip\string+\endcsname\relax{%
  SAT\textgreater IP%
}

\satip{x}在使用时会触发错误

! Use of \satip+ doesn't match its definition.
<argument> x

\satip ip不会。你应该这样做脚步:

\newcommand{\satip}{}% initialize
\protected\def\satip#{\csname satip\string+\endcsname}
\expandafter\def\csname satip\string+\endcsname#1{%
  \csname satip\string+\string+\endcsname #1\relax
}
\expandafter\def\csname satip\string+\string+\endcsname\relax{%
  SAT\textgreater IP%
}

现在\satip x\satip{x}都会触发错误:

! Use of \satip doesn't match its definition.
l.14 \satip x

? 
! Use of \satip++ doesn't match its definition.
<argument> x

l.16 \satip{x}

? 

注意\protected的定义前面\satip,因此它不会在“移动参数”上下文中展开。

摘要版本:

\documentclass{article}

\makeatletter
\newcommand\definestringcommand[2]{%
  \@ifdefinable#1{\@definestringcommand#1{#2}}%
}

\newcommand{\@definestringcommand}[2]{%
  \begingroup
  \escapechar=\m@ne % get rid of the backslash
  % require brace
  \protected\xdef#1##{\expandafter\noexpand\csname\string#1\string+\endcsname}%
  % examine the argument
  \expandafter\xdef\csname\string#1\string+\endcsname##1{%
    \expandafter\noexpand\csname\string#1\string+\string+\endcsname##1\relax
  }%
  \expandafter\gdef\csname\string#1\string+\string+\endcsname\relax{#2}%
  \endgroup
}
\makeatother

\definestringcommand{\satip}{SAT\textgreater IP}

\begin{document}

\satip is nice

\satip{x} is nice

\satip{} is nice

\end{document}

这是否有用,我把决定权留给你。

不同的实现:检查{,然后检查以下内容,}如果成功则吃掉两个令牌。

\documentclass{article}

\makeatletter
\newcommand\definestringcommand[2]{%
  \@ifdefinable#1{\@definestringcommand#1{#2}}%
}

\newcommand{\@definestringcommand}[2]{%
  \begingroup
  \escapechar=\m@ne % get rid of the backslash
  % require brace
  \protected\xdef#1##{%
    \expandafter\noexpand\csname\string#1\string+\endcsname
  }%
  \expandafter\gdef\csname\string#1\string+\endcsname{%
    #2%
    \afterassignment\@checkrightbrace\let\@forget= % the space counts
  }
  \endgroup
}
\newcommand{\@checkrightbrace}{%
  \@ifnextchar\egroup{\let\@forget= }{\@strcmderr\let\@forget= }%
}
\newcommand{\@strcmderr}{%
  \@latex@error{Non empty group}{The braces must contain nothing}%
}
\makeatother

\definestringcommand{\satip}{SAT\textgreater IP}

\begin{document}

\satip is nice

\satip{x} is nice

\satip{} is nice

\end{document}

相关内容