Недостатки метода csname для избежания пробелов после команды

Недостатки метода csname для избежания пробелов после команды

У меня была похожая проблема:Пробел после команд LaTeX

Моя первая попытка была примерно такой:

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

Это приводит к известной проблеме, заключающейся в том, что пробелы после команды съедаются:

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

Я поискал и нашел упомянутый вопрос. Предоставленные решения очень помогли, но я не был полностью доволен ни одним из них. \satip/просто выглядит немного странно в документе latex, мне нравится \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

Теперь мой вопрос:

Этот макрос требует второго шага расширения. Может ли это вызвать какие-либо проблемы? Есть ли другие проблемы? (Поскольку я нигде этого раньше не находил.)

PS: Извините за неудачное название, ничего лучшего не придумал. Можете редактировать.

решение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}

Связанный контент