[Tex/LaTex] Proper way to detect empty/blank text

conditionalsmacrosspacing

I am attempting to ignore a command if it is passed with empty/blank text. My use case is not as complicated as one Expand away empty macros within ifthenelse where @egreg provides what seems like a great way to test if the text passed to it would produce no output. However, I can't seem to get it to work.

When the following works the output should be just the name (if no address or an empty/blank address is given):

Name: Peter's Pizza

or if a non-blank address is given:

Name: Peter's Pizza

Address: 123 Main Street, Anytown, USA

xstring Version of IfNoText:

With my original version (with %\def\UseEgregsIfNoText{} commented out), Section 1 and 3 are correct.

Section 2 does not work properly in that the Address: is printed when it should not be. This xstring version of \IfNoText also does not allow me to have blank lines in the \SetAddress{} (see second occurrence of \UseEgregsIfNoText) which I would like.

Furthermore, Section 4 shows that I am not able to compile if I attempt to access \MandatoryName. Note that it is commented out in this case.

enter image description here

Egreg's Version of IfNoText:

With @egreg's version of \IfNoText (uncomment \def\UseEgregsIfNoText{}) obtained from Expand away empty macros within ifthenelse, I can compile with blank lines in the \SetAddress{} and use the \MandatoryName macro, but don't get the desired results. Here Case 1 and 2 are correct, but not 3 (which has additional blank lines inserted in \SetAddress) and 4 (which attempts to access the value of \MandatoryName).

enter image description here

Notes:

  • I was planning to use \IgnoreSpacesAndImplicitePars and \IgnoreSpacesAndAllPars from Looking for an \ignorespacesandpars, but they don't seem to make a difference. These macros are included in the code below but are not used
  • egreg does warn that tricky cases might fool “, but I don't think that blank lines was what he meant.

Code:

\def\UseEgregsIfNoText{}% 

\documentclass{article}
\usepackage{xspace}
\usepackage{xstring}

% https://tex.stackexchange.com/questions/23100/looking-for-an-ignorespacesandpars/23110#23110
\makeatletter
\def\IgnoreSpacesAndImplicitePars{%  Not used
  \begingroup
  \catcode13=10
  \@ifnextchar\relax
    {\endgroup}%
    {\endgroup}%
}

\def\IgnoreSpacesAndAllPars{%       Not used
  \begingroup
  \catcode13=10
  \@ifnextchar\par
    {\endgroup\expandafter\IgnoreSpacesAndAllPars\@gobble}%
    {\endgroup}%
}
\makeatother

\ifdefined\UseEgregsIfNoText
    %% https://tex.stackexchange.com/questions/42280/expand-away-empty-macros-within-ifthenelse
    \newcommand{\IfNoText}[3]{%
        \sbox0{#1}%
        \ifdim\wd0=0pt %
            {#2}% if #1 is empty
        \else%
            {#3}% if #1 is not empty
        \fi%
    }
\else
    \newcommand{\IfNoText}[3]{%
        %\edef\Parameter{\IgnoreSpacesAndAllPars#1}
        %\IfStrEq{\Parameter}{\empty}{#2}{#3}%
        \IfStrEq{#1}{\empty}{#2}{#3}%
    }
\fi


\newcommand*{\MandatoryName}{\empty}%
\newcommand*{\SetName}[1]{\renewcommand*{\MandatoryName}{#1\xspace}}%

\newcommand{\OptionalAddress}{\empty}% can have line breaks, so no "*"
\newcommand{\SetAddress}[1]{%
    \IfNoText{#1}{% 
        % No printable text so ignore...
    }{%
        \renewcommand{\OptionalAddress}{\ignorespaces#1}%
    }%
}%

\newcommand*{\ShowNameAndAddress}{%
    \par\noindent\textbf{Name:}~\MandatoryName
    \IfNoText{\OptionalAddress}{}{%
        \par\noindent\textbf{Address:}~\OptionalAddress
    }%
}%
\begin{document}
\section{Name with no Address}
\SetName{Peter's Pizza}
\ShowNameAndAddress

\section{Name with Empty address}
\ifdefined\UseEgregsIfNoText
    % Want to be able to handle this:
    \SetAddress{


    }
\else
    \SetAddress{
    }
\fi

\ShowNameAndAddress


\section{Name with Address Given}

\SetAddress{
  123 Main Street,
  Anytown, USA
}

\ShowNameAndAddress

\section{Name with Address using Name}

%Verify: \verb|\MandatoryName =| \MandatoryName

\ifdefined\UseEgregsIfNoText
    % Want to be able to access value of \MandatoryName here
    \SetAddress{
      123 \MandatoryName Way,
      Anytown, USA
    }
\else
    % Can't even compile in this case with \MandatoryName 
    \SetAddress{
      123 %\MandatoryName Way,
      Anytown, USA
    }
\fi

\ShowNameAndAddress

\end{document}

Best Answer

Here's how I would write it.

\makeatletter
\newcommand{\DoIfNoText}[1]{%
  \begingroup
  \sbox0{#1}%
  \ifdim\wd0=\z@
    \endgroup
    \expandafter\@gobble
  \else
    \endgroup
    \expandafter\@firstofone
  \fi}
\makeatother
\newcommand{\MandatoryName}{}
\newcommand{\SetName}[1]{\renewcommand{\MandatoryName}{#1}}

\newcommand{\OptionalAddress}{}
\newcommand{\SetAddress}[1]{%
  \DoIfNoText{#1}
    {\renewcommand{\OptionalAddress}{\ignorespaces#1}}%
  }

\newcommand{\ShowNameAndAddress}{%
  \par\noindent\textbf{Name:}~\MandatoryName
  \DoIfNoText{\OptionalAddress}
    {\par\noindent\textbf{Address:}~\OptionalAddress}%
  }

Probably

\def\OptionalAddress{}

should be added to \ShowNameAndAddress if you want to avoid the meaning of \OptionalAddress to be carried over to the next address.

Blank lines in the argument of \DoIfNoText are irrelevant, as the box is built in restricted horizontal mode, where \par commands are ignored.

Note I've added a \begingroup-\endgroup pair to keep the assignment to \box0 local, thus avoiding possible conflicts in some situations (see Missing Item number in enumerate and Frank Mittelbach's answer).

Related Question