6

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

  • 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 Nov 18 '14 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 Nov 18 '14 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 Nov 18 '14 at 14:18
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}
  • Why do you need the first \expandafter? – SJU Nov 18 '14 at 14:09
  • @AngelTsankov You don't (I originally had a different version, will remove, thanks) – David Carlisle Nov 18 '14 at 14:10
  • How about just \if\relax\detokenize\expandafter{#1}\relax empty\else not empty\fi? – SJU Nov 18 '14 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). – Bruno Le Floch Nov 18 '14 at 18:10
  • 1
    @BrunoLeFloch the X#1X saves me, as Angel says:-) – David Carlisle Nov 18 '14 at 18:40
1

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.