6

How can I test in a safe way (i.e. without reserving tokens as explained here) if an expanded macro argument is empty?

3
  • I do not understand what do you mean by “expanded” (i.e., why is it relevant here). In your link the answer says “The safest way is \if\relax\detokenize{#1}\relax”. What “safe way” are you looking for?
    – Manuel
    Commented Nov 18, 2014 at 12:38
  • @Manuel Basically, I am looking for a test if a macro argument expands to nothing. (\if\relax\detokenize{#1}\relax fails when passed \empty, defined as \def\empty{}.) A safe test is one that is generic enough not to rely on a token not being in the argument.
    – SJU
    Commented Nov 18, 2014 at 12:52
  • 2
    @AngelTsankov The \if\relax\detokenize{#1}\relax isn't relying on anything: if the argument is \empty then it's not empty. So while 'how do I test if the full expansion of an argument' is a perfectly valid question, it's not due to anything 'unsafe' in the test for an empty argument.
    – Joseph Wright
    Commented Nov 18, 2014 at 14:18

3 Answers 3

6

You can use a \romannumeral trick:

\if\relax\detokenize\expandafter{\romannumeral-`\Q#1}\relax

The missing space after `\Q will trigger expansion of #1 (after macro substitution, of course). Since this expansion ends at the first unexpandable token, this should be what you want.

However a leading space will be ignored.

\def\notempty{\relax}
\def\perhapsempty{\empty}

\if\relax\detokenize\expandafter{\romannumeral-`\Q\empty}\relax
  \message{EMPTY}
\else
  \message{NOT EMPTY}
\fi

\if\relax\detokenize\expandafter{\romannumeral-`\Q\notempty}\relax
  \message{EMPTY}
\else
  \message{NOT EMPTY}
\fi

\if\relax\detokenize\expandafter{\romannumeral-`\Q\perhapsempty}\relax
  \message{EMPTY}
\else
  \message{NOT EMPTY}
\fi

\if\relax\detokenize\expandafter{\romannumeral-`\Q\space}\relax
  \message{EMPTY}
\else
  \message{NOT EMPTY}
\fi

This is pdfTeX, Version 3.14159265-2.6-1.40.15 (TeX Live 2014) (preloaded format=pdftex)
 restricted \write18 enabled.
entering extended mode
(./tsanempty.tex EMPTY NOT EMPTY EMPTY EMPTY)

If you don't need expandability and trust that the tokens you pass are fully expandable, you can use \edef:

\begingroup\edef\x{#1}\expandafter\endgroup\expandafter
\if\expandafter\relax\detokenize\expandafter{\x}\relax

For instance,

\begingroup\edef\x{\empty}\expandafter\endgroup\expandafter
\if\expandafter\relax\detokenize\expandafter{\x}\relax
  \message{EMPTY}
\else
  \message{NOT EMPTY}
\fi

\begingroup\edef\x{\notempty}\expandafter\endgroup\expandafter
\if\expandafter\relax\detokenize\expandafter{\x}\relax
  \message{EMPTY}
\else
  \message{NOT EMPTY}
\fi

\begingroup\edef\x{\perhapsempty}\expandafter\endgroup\expandafter
\if\expandafter\relax\detokenize\expandafter{\x}\relax
  \message{EMPTY}
\else
  \message{NOT EMPTY}
\fi

\begingroup\edef\x{\space}\expandafter\endgroup\expandafter
\if\expandafter\relax\detokenize\expandafter{\x}\relax
  \message{EMPTY}
\else
  \message{NOT EMPTY}
\fi

will return

EMPTY NOT EMPTY EMPTY NOT EMPTY

Actually, an \expandafter is redundant, but clarity is better.

5

enter image description here

\documentclass{article}
\usepackage[T1]{fontenc}

\def\foo#1{\par \texttt{<\detokenize{#1}>} 
\expandafter\if\relax\detokenize\expandafter{\romannumeral0#1}\relax
\if X#1X%
empty\else
not empty\fi
\else
not empty\fi}

\begin{document}
\foo{}

\foo{ }

\foo{\empty}

\foo{{}}

\foo{\sqrt}

\foo{\csname @gobble\endcsname{hello}}

\end{document}
7
  • Why do you need the first \expandafter?
    – SJU
    Commented Nov 18, 2014 at 14:09
  • @AngelTsankov You don't (I originally had a different version, will remove, thanks) Commented Nov 18, 2014 at 14:10
  • How about just \if\relax\detokenize\expandafter{#1}\relax empty\else not empty\fi?
    – SJU
    Commented Nov 18, 2014 at 14:13
  • 1
    This answer is wrong, as it will consider 0 to be empty. See egreg's answer for a correct use of \romannumeral in this context (sorry David). Commented Nov 18, 2014 at 18:10
  • 1
    @BrunoLeFloch the X#1X saves me, as Angel says:-) Commented Nov 18, 2014 at 18:40
2

Have you tried the ifmtarg package? It provides the macro

\@ifmtarg{<arg>}{<Code for arg empty>}
                {<Code for arg not empty>}

Use texdoc ifmtarg for the documentation.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .