У меня была похожая проблема:Пробел после команд 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}