为什么这个 \ifx 不测试宏是否为空?

为什么这个 \ifx 不测试宏是否为空?

考虑以下 MWE:

\documentclass{standalone}
\newcommand{\myname}{ss}
\newcommand{\mycmd}{\ifx\myname\undefined{Please enter your name}\else{Professor \myname}\fi}
\begin{document}
    \mycmd
\end{document}

我不知道为什么上面的命令返回Professor \myname是否\newcommand{\myname}{}为空?!

答案1

当然,您可以检查\myname标记列表的内容以确定它是否包含名称。但是,这种方法需要一定程度的解析,因为您(大概)正在制作用户界面。例如,如果用户做了\newcommand\myname{}\newcommand\myname{ }或根本\let\myname\relax没有定义\myname,则都需要不同的测试,这开始变得有点笨拙。

对于最简单的情况,即命令被定义/未定义,以及(如果已定义)为空/不为空,您可以编写两个嵌套条件;一个\ifx\myname\@undefined,另一个\ifx\myname\@empty1

\makeatletter
\newcommand{\mycmd}{%
  \ifx\myname\@undefined
    Please enter your name%
  \else
    \ifx\myname\@empty
      Please enter your name%
    \else
      Professor \myname
    \fi
  \fi}
\makeatother
\newcommand*{\myname}{ss}%

[1]通过这种方法,用户必须使用\newcommand*,否则\ifx\myname\@empty测试将失败,即使用户确实使用了\newcommand{\myname}{ss}。为了允许两个都 \newcommand\newcommand*需要其他嵌套条件\ifx\myname\long@empty然后定义\long\def\long@empty{}。它很快就会变得无法维护。


这是一个稍微好一点的用户界面(用户不必知道\newcommand),它已经告诉代码是否给出了名称(不管名称实际上是什么)。

该命令\setname(与 LaTeX 的 非常相似\author)定义了包含名称的标记列表\myname,并将条件设置\if@name@set\iftrue。如果\setname没有使用 ,则为\if@name@set并且\iffalse包含\myname默认值。

\documentclass{article}

\makeatletter
\newcommand{\setname}[1]{%
  \let\if@name@set\iftrue
  \gdef\myname{#1}}
\let\if@name@set\iffalse
\gdef\myname{Please enter your name}
\newcommand{\mycmd}{%
  \if@name@set
    Professor \myname
  \else
    \textbf{??\myname??}%
  \fi}
\makeatother

\begin{document}
\mycmd

\setname{X}% set the name
\mycmd % print again
\end{document}

在此处输入图片描述

答案2

Phelype 的回答解释了许多问题。

但还有另一种方法:

\documentclass{standalone}

\newcommand{\mycmd}{%
  \ifdefined\myname
    Professor \myname
  \else
    Please enter your name%
  \fi
}

\newcommand{\myname}{ss}

\begin{document}

\mycmd

\end{document}

对于这种编程,通常最好使用“私有”命令,以便涵盖用户可能\myname为自己的目的而定义的可能操作。

当然,主要代码应该放在.sty或文件中。.cls

\documentclass{standalone}

\makeatletter % <- this should not appear in a .sty or .cls file
%% code for .sty or .cls
\newcommand{\printadvisor}{%
  \ifdefined\cfg@advisor
    Professor \cfg@advisor
  \else
    \PackageWarning{cfgpackage}{Missing advisor's name}% or \ClassWarning
    Please enter advisor's name%
  \fi
}

\newcommand{\setadvisor}[1]{\gdef\cfg@advisor{#1}}
%% end of code for .sty or .cls
\makeatother % <- this should not appear in a .sty or .cls file

\begin{document}

%% in the document “metadata part”
\setadvisor{A. Einstein}

\printadvisor

\end{document}

答案3

我可以提供一个\romannumeral0基于 -expansion 的例程\UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined来检查宏参数是否由未定义或定义为空白的单个标记组成。(“定义为空白”意味着扩展标记要么根本不产生标记,要么只产生空格标记。)

该例程不需要 ε-TeX 扩展或类似的东西,也可以在扩展上下文中应用,例如在 内\csname..\endcsname。结果将在两个扩展步骤/两次“命中”后提供\expandafter

该例程不使用任何\if..\else..\fi
该例程不会因其参数中的 (unbalanced) \if../ \else/\fi或 unbalanced \csname/而感到困惑。\endcsname

例行公事将不扩大参数,它只会“查看”由第一个参数形成的标记集,以“决定”是否要传递形成第二个参数的标记或形成第三个参数的标记。


可能的陷阱:如果参数是单个宏标记,且不处理参数,则检查该宏标记是否定义为空白,方法是通过 LaTeX 2ε-kernel-macro剥离前缀 (-thingie) 后“查看”\meaning宏标记的。“查看”宏标记的含义而不是“查看”宏标记的顶层扩展是为了确保在宏标记扩展为 的情况下测试不会失败。(您可以执行以下操作:\UD@CheckWhetherBlankmacro:->\strip@prefix\outer

\def\unfold{\umbrella}
\outer\def\umbrella{No raindrops on my head, please!}

\unfold并将扩展为 ,\umbrella\outer。在这种情况下,直接将顶层扩展的结果\unfold作为参数传递给宏来检查该扩展的空白性是不可能的,因为这意味着将 -token\outer作为宏参数的组成部分。)
但在这种情况下查看含义并不完全安全:如果整数参数的\escapechar值为 32(32 是 ASCII 和 Unicode 中空格字符的代码点数,这是当今 TeX 引擎的可能内部字符编码方案),或者其值超出了 TeX 引擎内部字符编码方案的可能代码点数范围,则检查“含义的空白性”不会产生令牌被定义为也提供名称仅由空格组成的控制序列的情况,例如控制空间,或通过 构造的东西\csname..\endcsname,例如:

\def\insertfivechars#1#2{#1#2#2#2#2#2}
\insertfivechars{\expandafter\def\csname}{ }\endcsname{The name of this control sequence consists of five spaces.}
\insertfivechars{\expandafter\show\csname}{ }\endcsname
% But:
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\scratch
\expandafter\expandafter\expandafter{%
  \insertfivechars{\csname}{ }\endcsname
}
\escapechar=-1
\message{X\meaning\scratch X}
\bye

为了好玩,检查标记是否未定义是通过检查应用结果是否\meaning提供以标记开头的标记序列来完成的。u12n12d12e12f12i12n12e12d12

可能检查含义是否以或开头就足够了。 [如果有人能验证这一点并添加评论,我会很高兴也很感激。;-)]u12u12n12

附录:
我不知道问这个问题时我在想什么。
例如,有一个-primitive,这意味着当具有正值时\uppercase,检查是不够的。u12\escapechar
菲利佩·奥莱尼克指出\escapechar需要考虑的值,并且存在\underline-原语,因此至少需要检查。u12n12d12e12f12


\UD@CheckWhetherNull我对这个问题的回答详细解释了空测试“空标记列表的可扩展测试——方法、性能和稳健性”. 在那个答案中它的名字不是\UD@CheckWhetherNull而是\CheckWhetherEmpty


\documentclass[a4paper]{article}

%===================[adjust margins/layout for the example]====================
\csname @ifundefined\endcsname{pagewidth}{}{\pagewidth=\paperwidth}%
\csname @ifundefined\endcsname{pdfpagewidth}{}{\pdfpagewidth=\paperwidth}%
\csname @ifundefined\endcsname{pageheight}{}{\pageheight=\paperheight}%
\csname @ifundefined\endcsname{pdfpageheight}{}{\pdfpageheight=\paperheight}%
\textwidth=\paperwidth
\oddsidemargin=1.25cm
\marginparsep=.125\oddsidemargin
\marginparwidth=\oddsidemargin
\advance\marginparwidth-2\marginparsep
\advance\textwidth-2\oddsidemargin
\advance\oddsidemargin-1in
\evensidemargin=\oddsidemargin
\textheight=\paperheight
\topmargin=1.25cm
\footskip=.5\topmargin
{\normalfont\global\advance\footskip.5\ht\strutbox}%
\advance\textheight-2\topmargin
\advance\topmargin-1in
\headheight=0ex
\headsep=0ex
\pagestyle{empty}
\parindent=0ex
\parskip=0ex 
\topsep=0ex
\partopsep=0ex
%==================[eof margin-adjustments]====================================

\makeatletter
%=====[code for \UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined]=======
%% Check whether argument is empty:
%%.............................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is empty>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\UD@CheckWhetherNull[1]{%
  \romannumeral0\expandafter\@secondoftwo\string{\expandafter
  \@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
  \@secondoftwo\string}\@firstoftwo\expandafter{} \@secondoftwo}%
  {\@firstoftwo\expandafter{} \@firstoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Check whether argument is blank (empty or only spaces):
%%.............................................................................
%% -- Take advantage of the fact that TeX discards space tokens when
%%    "fetching" _un_delimited arguments: --
%% \UD@CheckWhetherBlank{<Argument which is to be checked>}%
%%                      {<Tokens to be delivered in case that
%%                        argument which is to be checked is blank>}%
%%                      {<Tokens to be delivered in case that argument
%%                        which is to be checked is not blank>}%
\newcommand\UD@CheckWhetherBlank[1]{%
  \romannumeral\expandafter\expandafter\expandafter\@secondoftwo
  \expandafter\UD@CheckWhetherNull\expandafter{\@firstoftwo#1{}.}%
}%
%%-----------------------------------------------------------------------------
%% Check whether argument's first token is a catcode-1-character
%%.............................................................................
%% \UD@CheckWhetherBrace{<Argument which is to be checked>}%
%%                      {<Tokens to be delivered in case that argument
%%                        which is to be checked has leading
%%                        catcode-1-token>}%
%%                      {<Tokens to be delivered in case that argument
%%                        which is to be checked has no leading
%%                        catcode-1-token>}%
\newcommand\UD@CheckWhetherBrace[1]{%
  \romannumeral0\expandafter\@secondoftwo\expandafter{\expandafter{%
  \string#1.}\expandafter\@firstoftwo\expandafter{\expandafter
  \@secondoftwo\string}\expandafter\expandafter\@firstoftwo{ }{}%
  \@firstoftwo}{\expandafter\expandafter\@firstoftwo{ }{}\@secondoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Exchange two arguments. (From each argument an outermost level of 
%% surrounding braces will be removed if present.)
%%-----------------------------------------------------------------------------
\newcommand\UD@Exchange[2]{#2#1}%
%%-----------------------------------------------------------------------------
%% Check whether argument's leading tokens form a specific 
%% token-sequence that does not contain explicit character tokens of 
%% category code 1 or 2:
%%.............................................................................
%% \UD@CheckWhetherLeadingTokens{<argument which is to be checked>}%
%%                              {<a <token sequence> without explicit 
%%                                character tokens of category code
%%                                1 or 2>}%
%%                              {a <single non-space token> that does 
%%                                _not_ occur in <token sequence> >}%
%%                              {<internal token-check-macro>}%
%%                              {<tokens to be delivered in case
%%                                <argument which is to be checked> has
%%                                <token sequence> as leading tokens>}%
%%                              {<tokens to be delivered in case 
%%                                <argument which is to be checked>
%%                                does not have <token sequence> as
%%                                leading tokens>}%
\newcommand\UD@CheckWhetherLeadingTokens[4]{%
  \romannumeral0\UD@CheckWhetherNull{#1}%
  {\UD@Exchange{ }\expandafter\@secondoftwo}%
  {\expandafter\@secondoftwo\string{\expandafter
   \UD@@CheckWhetherLeadingTokens#4#3#1#2}{}}%
}%
\newcommand\UD@@CheckWhetherLeadingTokens[1]{%
  \expandafter\UD@CheckWhetherNull\expandafter{\@firstoftwo{}#1}%
  {\UD@Exchange{\@firstoftwo}}{\UD@Exchange{\@secondoftwo}}%
  {\UD@Exchange{ }{\expandafter\expandafter\expandafter\expandafter
   \expandafter\expandafter\expandafter}\expandafter\expandafter
   \expandafter}\expandafter\@secondoftwo\expandafter{\string}%
}%
%%-----------------------------------------------------------------------------
%% \UD@internaltokencheckdefiner{<internal token-check-macro>}%
%%                              {<token sequence>}%
%% Defines <internal token-check-macro> to snap everything 
%% until reaching <token sequence>-sequence and spit that out
%% nested in braces.
%%-----------------------------------------------------------------------------
\newcommand\UD@internaltokencheckdefiner[2]{%
  \@ifdefinable#1{\long\def#1##1#2{{##1}}}%
}%
\begingroup
%%-----------------------------------------------------------------------------
%% Check whether argument is a macro that takes arguments
%%.............................................................................
%% Temporary/interim-definition/Usage as scratch-macro:
\newcommand\UD@CheckWhetherArgumentlessMacroMeaning[5]{%
  % #1 = phrase "undefined" in catcode-12-character-tokens
  % #2 = phrase "macro:->" in catcode-12-character-tokens
  % #3 = phrase "\long macro:->" in catcode-12-character-tokens
  % #4 = phrase "\protected\long macro:->" in catcode-12-character-tokens
  % #5 = phrase "\protected macro:->" in catcode-12-character-tokens
  \endgroup
  \UD@internaltokencheckdefiner{\UD@ExtractUndefined}{#1}%
  \UD@internaltokencheckdefiner{\UD@ExtractMacro}{#2}%
  \UD@internaltokencheckdefiner{\UD@ExtractLongMacro}{#3}%
  \UD@internaltokencheckdefiner{\UD@ExtractProtectedLongMacro}{#4}%
  \UD@internaltokencheckdefiner{\UD@ExtractProtectedMacro}{#5}%
  \UD@internaltokencheckdefiner{\UD@ExtractSpace}{ }%
  %%-----------------------------------------------------------------------------
  %% Check whether argument is a macro that takes arguments
  %%.............................................................................
  %% \expandafter\UD@CheckWhetherArgumentlessMacroMeaning
  %% \expandafter{\meaning <token>}{%
  %%   <Tokens to be delivered in case <token> is a macro that does not take 
  %%    arguments>
  %% }{%
  %%   <Tokens to be delivered in case <token> is not a macro that does not 
  %%    take arguments>
  %% }%
  \newcommand\UD@CheckWhetherArgumentlessMacroMeaning[1]{%
    \UD@CheckWhetherLeadingTokens{##1}{#2}{.}{\UD@ExtractMacro}{\@firstoftwo}{%
      \UD@CheckWhetherLeadingTokens{##1}{#3}{.}{\UD@ExtractLongMacro}{\@firstoftwo}{%
        \UD@CheckWhetherLeadingTokens{##1}{#4}{.}{\UD@ExtractProtectedLongMacro}{\@firstoftwo}{%
          \UD@CheckWhetherLeadingTokens{##1}{#5}{.}{\UD@ExtractProtectedMacro}{\@firstoftwo}{%
            \@secondoftwo
          }%
        }%
      }%
    }%
  }%
  %%-----------------------------------------------------------------------------
  %% Check whether argument is a token that is undefined and can be defined.
  %%.............................................................................
  %% \expandafter\UD@CheckWhetherUndefinedMeaning
  %% \expandafter{\meaning <token>}{%
  %%   <Tokens to be delivered in case <token> is undefined and can be defined.>
  %% }{%
  %%   <Tokens to be delivered in case <token> is not undefined/cannot be
  %%    defined.>
  %% }%
  \newcommand\UD@CheckWhetherUndefinedMeaning[1]{%
    \UD@CheckWhetherLeadingTokens{##1}{#1}{.}{\UD@ExtractUndefined}%
  }%
}%
\def\@tempa{\protected macro:->}\@onelevel@sanitize\@tempa
\expandafter\UD@Exchange\expandafter{\expandafter{\@tempa}}{%
  \edef\@tempa{\string\protected\long macro:->}\@onelevel@sanitize\@tempa
  \expandafter\UD@Exchange\expandafter{\expandafter{\@tempa}}{%
    \def\@tempa{\long macro:->}\@onelevel@sanitize\@tempa
    \expandafter\UD@Exchange\expandafter{\expandafter{\@tempa}}{%
      \def\@tempa{macro:->}\@onelevel@sanitize\@tempa
      \expandafter\UD@Exchange\expandafter{\expandafter{\@tempa}}{%
        \def\@tempa{undefined}\@onelevel@sanitize\@tempa
        \expandafter\UD@Exchange\expandafter{\expandafter{\@tempa}}{%
          \UD@CheckWhetherArgumentlessMacroMeaning
        }%
      }%
    }%
  }%
}%
%%-----------------------------------------------------------------------------
%% Check whether argument is undefined or defined blank (=yields no tokens or
%% only space-tokens)/a single token:
%%.............................................................................
%% \UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined{%
%%   <Argument which is to be checked>%
%% }{%
%%   <Tokens to be delivered in case <argument which is to be checked> is a
%%    single token that is undefined or defined blank>%
%% }{%
%%   <Tokens to be delivered in case <argument which is to be checked> is not a
%%    single token that is undefined or defined blank>%
%% }%
\newcommand\UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined[1]{%
  \romannumeral0%
  \UD@CheckWhetherBlank{#1}{%
    % Argument is blank:
    \@firstoftwo\expandafter{} \@secondoftwo
  }{%
    \UD@CheckWhetherBrace{#1}{%
      % The leading opening brace implies that further examination
      % is not needed:
      \@firstoftwo\expandafter{} \@secondoftwo
    }{%
      % Argument's first token is not an opening brace and
      % therefore its first token can safely be "hit" by \meaning:
      \UD@CheckWhetherLeadingTokens{#1}{ }{.}{\UD@ExtractSpace}%
      {%
        % Argument has a leading space. Thus argument's first token
        % cannot be removed by "gobbling" a non-delimited argument.
        % The leading space implies that further examination
        % is not needed:
        \@firstoftwo\expandafter{} \@secondoftwo
      }{%
        % Argument's first token is a non-space-token that can safely be
        % gobbled and argument's first token can safely be "hit" by
        % \meaning:
        \expandafter\UD@CheckWhetherNull\expandafter{\@firstoftwo{}#1}{%
          % Argument consists of a single token which can safely be "hit"
          % by \meaning:
          \expandafter\UD@CheckWhetherUndefinedMeaning\expandafter{\meaning#1}%
          {%
            %The meaning denotes that the single token is undefined:
            \@firstoftwo\expandafter{} \@firstoftwo
          }%
          {%
            %The meaning denotes that the single token is not undefined:
            \expandafter\UD@CheckWhetherArgumentlessMacroMeaning\expandafter{\meaning#1}%
            {%
              %The meaning denotes that the single token is an argumentless macro:
              \expandafter\expandafter
              \expandafter            \UD@CheckWhetherBlank
              \expandafter\expandafter
              \expandafter            {%
              \expandafter\strip@prefix
              \meaning#1}{%
                %The meaning denotes that the single token is defined blank:
                %In the edge case of `\escapechar` having a negative value or
                %having the value 32 (32 is the code-point of the space character
                %both in ASCII and in Unicode, the possible internal coding-schemes
                %of TeX-engines), the definition of the token might also
                %contain control sequences whose name consists of spaces
                %only, e.g., control spaces \ .
                \@firstoftwo\expandafter{} \@firstoftwo
              }{%
                %The meaning denotes that the single token is defined, but not blank:
                \@firstoftwo\expandafter{} \@secondoftwo
              }%
            }%
            {%
              %The meaning denotes that the single token is not an argumentless macro:
              \@firstoftwo\expandafter{} \@secondoftwo
            }%
          }%
        }{%
          % Argument consists of several tokens and the argument's
          % first token neither is a space nor is a brace:
          % The circumstance of there being severak tokens implies that 
          % further examination is not needed:
          \@firstoftwo\expandafter{} \@secondoftwo
        }%
      }%
    }%
  }%
}%
%%===[eof code for \UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined]====
\makeatother

\begin{document}
\makeatletter

\begin{verbatim}
\UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined{\UndEFiNeD}{%
   Arg is a single token which is definable and either currently undefined or defined blank.
}{%
   Arg is a not a single token which is definable and either currently undefined or defined blank.
}%
\end{verbatim}

yields:

\UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined{\UndEFiNeD}{%
   Arg is a single token which is definable and either currently undefined or defined blank.
}{%
   Arg is a not a single token which is definable and either currently undefined or defined blank.
}%

\noindent\null\hrulefill

\begin{verbatim}
\UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined{\UndEFiNeD\UndEFiNeD}{%
   Arg is a single token which is definable and either currently undefined or defined blank.
}{%
   Arg is a not a single token which is definable and either currently undefined or defined blank.
}%
\end{verbatim}

yields:

\UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined{\UndEFiNeD\UndEFiNeD}{%
   Arg is a single token which is definable and either currently undefined or defined blank.
}{%
   Arg is a not a single token which is definable and either currently undefined or defined blank.
}%

\noindent\null\hrulefill

\begin{verbatim}
\UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined{}{%
   Arg is a single token which is definable and either currently undefined or defined blank.
}{%
   Arg is a not a single token which is definable and either currently undefined or defined blank.
}%
\end{verbatim}

yields:

\UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined{}{%
   Arg is a single token which is definable and either currently undefined or defined blank.
}{%
   Arg is a not a single token which is definable and either currently undefined or defined blank.
}%

\noindent\null\hrulefill

\begin{verbatim}
\UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined{  }{%
   Arg is a single token which is definable and either currently undefined or defined blank.
}{%
   Arg is a not a single token which is definable and either currently undefined or defined blank.
}%
\end{verbatim}

yields:

\UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined{  }{%
   Arg is a single token which is definable and either currently undefined or defined blank.
}{%
   Arg is a not a single token which is definable and either currently undefined or defined blank.
}%

\noindent\null\hrulefill

\begin{verbatim}
\UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined{\LaTeX}{%
   Arg is a single token which is definable and either currently undefined or defined blank.
}{%
   Arg is a not a single token which is definable and either currently undefined or defined blank.
}%
\end{verbatim}

yields:

\UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined{\LaTeX}{%
   Arg is a single token which is definable and either currently undefined or defined blank.
}{%
   Arg is a not a single token which is definable and either currently undefined or defined blank.
}%

\noindent\null\hrulefill

\begin{verbatim}
\UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined{\@firstoftwo}{%
   Arg is a single token which is definable and either currently undefined or defined blank.
}{%
   Arg is a not a single token which is definable and either currently undefined or defined blank.
}%
\end{verbatim}

yields:

\UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined{\@firstoftwo}{%
   Arg is a single token which is definable and either currently undefined or defined blank.
}{%
   Arg is a not a single token which is definable and either currently undefined or defined blank.
}%

\noindent\null\hrulefill

\begin{verbatim}
\UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined{\empty}{%
   Arg is a single token which is definable and either currently undefined or defined blank.
}{%
   Arg is a not a single token which is definable and either currently undefined or defined blank.
}%
\end{verbatim}

yields:

\UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined{\empty}{%
   Arg is a single token which is definable and either currently undefined or defined blank.
}{%
   Arg is a not a single token which is definable and either currently undefined or defined blank.
}%

\noindent\null\hrulefill

\protected\long\def\myblank{ }%
\begin{verbatim}
\UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined{\myblank}{%
   Arg is a single token which is definable and either currently undefined or defined blank.
}{%
   Arg is a not a single token which is definable and either currently undefined or defined blank.
}%
\end{verbatim}

yields:

\UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined{\myblank}{%
   Arg is a single token which is definable and either currently undefined or defined blank.
}{%
   Arg is a not a single token which is definable and either currently undefined or defined blank.
}%

\noindent\null\hrulefill

\begin{verbatim}
\UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined{\myblank\myblank}{%
   Arg is a single token which is definable and either currently undefined or defined blank.
}{%
   Arg is a not a single token which is definable and either currently undefined or defined blank.
}%
\end{verbatim}

yields:

\UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined{\myblank\myblank}{%
   Arg is a single token which is definable and either currently undefined or defined blank.
}{%
   Arg is a not a single token which is definable and either currently undefined or defined blank.
}%

\noindent\null\hrulefill

\begin{verbatim}
\UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined{{\myblank}}{%
   Arg is a single token which is definable and either currently undefined or defined blank.
}{%
   Arg is a not a single token which is definable and either currently undefined or defined blank.
}%
\end{verbatim}

yields:

\UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined{{\myblank}}{%
   Arg is a single token which is definable and either currently undefined or defined blank.
}{%
   Arg is a not a single token which is definable and either currently undefined or defined blank.
}%

\noindent\null\hrulefill

\begin{verbatim}
\UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined{\else}{%
   Arg is a single token which is definable and either currently undefined or defined blank.
}{%
   Arg is a not a single token which is definable and either currently undefined or defined blank.
}%
\end{verbatim}

yields:

\UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined{\else}{%
   Arg is a single token which is definable and either currently undefined or defined blank.
}{%
   Arg is a not a single token which is definable and either currently undefined or defined blank.
}%

\noindent\null\hrulefill

\begin{verbatim}
\UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined{#}{%
   Arg is a single token which is definable and either currently undefined or defined blank.
}{%
   Arg is a not a single token which is definable and either currently undefined or defined blank.
}%
\end{verbatim}

yields:

\UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined{#}{%
   Arg is a single token which is definable and either currently undefined or defined blank.
}{%
   Arg is a not a single token which is definable and either currently undefined or defined blank.
}%

\noindent\null\hrulefill

\begin{verbatim}
\UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined{X}{%
   Arg is a single token which is definable and either currently undefined or defined blank.
}{%
   Arg is a not a single token which is definable and either currently undefined or defined blank.
}%
\end{verbatim}

yields:

\UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined{X}{%
   Arg is a single token which is definable and either currently undefined or defined blank.
}{%
   Arg is a not a single token which is definable and either currently undefined or defined blank.
}%

\noindent\null\hrulefill

\begin{verbatim}
\catcode`\X=13
\protected\defX{}%
\UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined{X}{%
   Arg is a single token which is definable and either currently undefined or defined blank.
}{%
   Arg is a not a single token which is definable and either currently undefined or defined blank.
}%
\end{verbatim}

yields:

\catcode`\X=13
\protected\defX{}%
\UD@CheckWhetherArgIsSingleTokenDefinedBlankOrUndefined{X}{%
   Arg is a single token which is definable and either currently undefined or defined blank.
}{%
   Arg is a not a single token which is definable and either currently undefined or defined blank.
}%

\end{document}

在此处输入图片描述 在此处输入图片描述

答案4

使用ifmtarg包(加上一些代码简化):

% undefprob.tex  SE 527084

\documentclass{standalone}
\usepackage{ifmtarg}
\makeatletter
\newcommand{\myname}[1]{\@ifmtarg{#1}{Please enter your name}%
                                     {Professor #1}}
\makeatother
%\newcommand{\mycmd}{\ifx\myname\undefined{Please enter your name}\else{Professor \myname}\fi}
\begin{document}
  Empty arg:  \myname{} 

  Non-empty arg: \myname{Jones}
\end{document}

上述代码检查 的参数是否为\myname空(空白)。如果为空,则要求输入姓名,否则打印 Professor 和 的参数\myname

相关内容