Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

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}

% http://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
    %% http://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}
share|improve this question
4  
Have a look at package ifmtarg - its purpose is to check for empty arguments. –  Michael Palmer Feb 18 '12 at 3:56
    
@MichaelPalmer: Did not know about that. The documentation looks promising. Do you want to post an answer showing how to use it for this case? –  Peter Grill Feb 18 '12 at 7:46
    
Please see below. –  Michael Palmer Feb 20 '12 at 2:24
    
It seems the main problem here is how to detect the empty lines in that address string (and possibly remove them to make it a real empty string so that egreg's \ifnotext will detect it). Right? Some kind of macro that can take the address string and remove all the non-text characters, seems to be the one that solves problem. I too would like to know if such macro exists, or how to write such macro - essentially we are looking at reading each character in the input string and ignore the whitespaces (spaces, tabs, newline, return chars) - the rest such as \textbf{} will be taken care by egreg's –  Gopalakrishna Palem Feb 23 '12 at 7:09
    
@GopalakrishnaPalem I converted your answer to a comment, since it's not a real answer. The space below is for actual answers. –  Stefan Kottwitz Feb 23 '12 at 7:58
show 1 more comment

5 Answers 5

up vote 4 down vote accepted

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).

share|improve this answer
    
This works great. But one thing I don't like about it is that the macro is defined as \newcommand{\DoIfNoText}[1], but takes two parameters. Does this not eliminate some error checking? Also, shouldn't this be called IgnoreIfNoText? –  Peter Grill Feb 18 '12 at 16:19
    
It's not necessary to scan the following argument twice; and error checking is just the same. The second argument is actually either to \@gobble or \@firstofone. –  egreg Feb 18 '12 at 16:29
add comment

The following things are worth mentioning:

  • Within \SetAddress, you redefine \OptionalAddress using

    \renewcommand{\OptionalAddress}{\ignorespaces#1}
    

    This definition only exists within \SetAddress. To see why this is the case, use \OptionalAddress just after setting the address, to see that nothing is typeset. So, you should rather use

    \gdef\OptionalAddress{\ignorespaces#1}
    

    which is short for \global\def. The reason being that you use \OptionalAddress in your \IfNoText test when calling \ShowNameandAddress.

  • A regular space spans 3.3333pt. However, it has no height or depth. So, perhaps you can change your definition of \IfNoText to

    \newcommand{\IfNoText}[3]{%
      \sbox0{#1}%
      \ifdim\wd0=0pt %
        {#2}% if #1 is empty
      \else%
        \ifdim0pt=\dimexpr\ht0+\dp0\relax
          {#2}% if #1 is empty
        \else
          {#3}% if #1 is not empty
        \fi
      \fi%
    

    which first checks to see if there is no width of the argument, followed by checking if there is no total height (height + depth), in the case of a space.

Including the above two suggestions yields:

enter image description here

\def\UseEgregsIfNoText{}% 

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

% http://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
    %% http://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%
          \ifdim0pt=\dimexpr\ht0+\dp0\relax
            {#2}
          \else
            {#3}% if #1 is not empty
          \fi
        \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...
    }{%
        \gdef\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}

I'm not saying this is the "proper" way. Just "a" way.

share|improve this answer
    
I disagree with your comment regarding the fact that "definition only exists within \SetAddress" (although I do see that it is needed for your code to work). Try commenting out %\def\UseEgregsIfNoText{}% and you'll see that \OptionalAddress actually prints something for section 3. Perhaps you can add some text to explain this issue. Other than that I think you have improved on an @egreg solution, for which there should be a badge. :-) –  Peter Grill Feb 18 '12 at 7:45
add comment

I am not sure this solves your problem, but for the record: package xifthen offers isempty. You can define a macro like this:

\newcommand{\ifempty}[3]{%
  \ifthenelse{\isempty{#1}}{#2}{#3}%
}
share|improve this answer
    
This does not seem to be able to handle blank lines. –  Peter Grill Feb 26 '12 at 17:55
    
@PeterGrill Nope, only "really" empty strings. You would have to trim your input first; see maybe here? –  Raphael Feb 26 '12 at 20:13
add comment

I want to show an alternative approach which is the result of @egreg, @JosephWright and me.

First of all I want to note that blank lines are a little bit strange, because a blank line sets everypar and this can be redefined.

Whatever here an approach using LaTeX3 in combination with xparse.

The argument typ m needs the prefix + to allow long arguments.

One special command is defined.

\prg_new_protected_conditional:Npnn \peter_if_blank_argument:N #1  {  T , F , TF }
{
   \hbox_set:Nn  \l_tmpa_box 
     {
      \tex_ignorespaces:D \tl_use:N #1 
     }
   \if_dim:w \box_wd:N \l_tmpa_box = \c_zero_dim 
    \prg_return_true:
   \else:
    \prg_return_false: 
   \fi:
 }

The function \prg_new_protected_conditional:Npnn allows us to define a new condition. The new function \peter_if_blank_argument:N saves the first argument inside a hbox and test whether the dim of the hbox is zero or not.

\documentclass{article}
\usepackage{expl3,xparse}
\ExplSyntaxOn
\tl_new:N \l_peter_setname_tl
\tl_new:N \l_peter_setaddress_tl

\NewDocumentCommand { \SetName} { +m }
 {
  \tl_set:Nn \l_peter_setname_tl { #1 }
 }

\NewDocumentCommand { \SetAddress} { +m }
 {
  \tl_set:Nn \l_peter_setaddress_tl { #1 }
 }


\prg_new_protected_conditional:Npnn \peter_if_blank_argument:N #1  {  T , F , TF }
 {
    \hbox_set:Nn  \l_tmpa_box 
     {
        \tex_ignorespaces:D \tl_use:N #1 
      }
   \if_dim:w    \box_wd:N \l_tmpa_box =    \c_zero_dim 
         \prg_return_true:
   \else:
          \prg_return_false: 
    \fi:
 }

\NewDocumentCommand { \ShowNameAndAddress } {  }
 {
  \peter_if_blank_argument:NF \l_peter_setname_tl 
      { \par \noindent  \textbf{Name:}~\tl_use:N  \l_peter_setname_tl }
  \peter_if_blank_argument:NF \l_peter_setaddress_tl 
      {
         \par \noindent  \textbf{Address:}~\tl_use:N \l_peter_setaddress_tl
       } 
  \tl_clear:N \l_peter_setname_tl
  \tl_clear:N \l_peter_setaddress_tl
 }

 \ExplSyntaxOff

\begin{document}
\section{Name with no Address}
\SetName{Peter's Pizza}
\SetAddress{


}
\ShowNameAndAddress

\end{document}
share|improve this answer
    
One of these days I will try to learn this syntax. But having problem adapting this to the last test case from my MWE where \MandatoryName is used in specifying the address. –  Peter Grill Feb 18 '12 at 16:29
    
@PeterGrill: We are taking about such code in the chat. Hope to see you there ;-) –  Marco Daniel Feb 18 '12 at 17:46
add comment

Here is another one:

\usepackage{ifthen}

\newcommand{\mycommand}[1]{%
\ifthenelse{\equal{#1}{}}{%
It is empty!%
}{%
It is not empty!%
}}
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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