4

I have some code for formatting names. However, the ifempty macro from xifthen is unable to detect empty/null output from xstring macros such as StrBetween. The same goes for the \equal {} method. How can I detect empty output from StrBetween? The below code for some reason compiles and does not work.

\documentclass{article}

\usepackage{xstring}
\usepackage{xifthen}

\newcommand{\name}{John Doe}

\newcommand{\middleinitial}{%
    \StrBetween{\name}{ }{.}
}

\newcommand{\test}{%
    \ifthenelse{\isempty{\middleinitial}}%
        {Whoo hoo!}%
        {Not whoo hoo.}
}

\begin{document}

\test

\end{document}

Any ideas?

2
4

\middleinitial is not expandable, and therefore you cannot properly test whether there is a middle initial in \name or not. You'll have to store the output (the middle initial) first using the optional argument at the end of \StrBetween{<str>}{<from>}{<to>}[<macro>] and then you can check for an empty argument:

enter image description here

\documentclass{article}

\usepackage{xstring}

\newcommand{\name}{John Doe}

\makeatletter
\newcommand{\middleinitial}{%
  \StrBetween{\name}{ }{.}[\@middleinitial]%
}

\newcommand{\test}{%
  \middleinitial% Find middle initial
  % https://tex.stackexchange.com/q/53068/5764
  \if\relax\detokenize\expandafter{\@middleinitial}\relax
    Whoo hoo!% No middle initial
  \else
    Not whoo hoo.% A middle initial
  \fi
}
\makeatother

\begin{document}

\test % Whoo hoo.

\renewcommand{\name}{John F. Doe}%
\test % Not whoo hoo!

\end{document}
16
  • What is this monstrosity: \expandafter\if\expandafter\relax\expandafter\detokenize\expandafter{\@middleinitial}\relax? – Adam Erickson Jan 13 '19 at 6:25
  • Also, thank you for your fast solution : ) Isn't it possible to do \StrBetween{\name}{ }{.}[\middleinitial] without the newcommand statement? – Adam Erickson Jan 14 '19 at 16:26
  • @AdamErickson: The monstrosity can be made shorter (updated in the answer). It's required to expand \@middleinitial before it being processed by \detokenize, hence the \expandafter. – Werner Jan 14 '19 at 16:30
  • @AdamErickson: You mean is it necessary to have a \newcommand{\middleinitial}? It's not necessary. You can include \StrBetween{\name}{ }{.}[\@middleinitial] as part of \test. – Werner Jan 14 '19 at 16:31
  • Thank you, that is much cleaner and easier to comprehend! – Adam Erickson Jan 14 '19 at 16:40
4

Werner already explained, why \middleinitial isn't expandable due to the usage of xstring macros.

I present a shorter way in order to test for the emptiness of \middleinitial by using \ifblank from etoolbox package. There are still two \expandafter statements required, but not a bunch of 5 of them. In addition, I find etoolbox much more convenient than ifthen or xifthen.

\expandafter\ifblank\expandafter{\middleinitial}{true branch}{false branch} is necessary, because \ifblank does not expand its first argument, i.e. without \expandafter the macro 'sees' \middleinitial, but not what the content which is stored in that macro. It must be expanded first before \ifblank performs the test.

The \expandafter primitive looks ahead of \ifblank, i.e. it ignores \ifblank first and detects the { of the first argument. Unfortunately, this is not what is desired (and not expandable anyway), so we must jump over { again, i.e.

\expandafter\ifblank\expandafter{\middleinitial}{...}{...}

will allow TeX/LaTeX to 'jump' over \ifblank to the second \expandafter, that jumps over { to \middleinitial and expands that sequence -- after this is done, TeX continues with \ifblank{expanded version of \middleinitial}{...}{...} and performs the test finally.

\documentclass{article}

\usepackage{xstring}
\usepackage{etoolbox}

\newcommand{\name}{John C.  Doe}

\newcommand{\othername}{John Doe}


\newcommand{\testinitial}[3]{%
  \begingroup
  \StrBetween{#1}{ }{.}[\middleinitial]%
  \expandafter\ifblank\expandafter{\middleinitial}{#2}{#3}%
  \endgroup
}


\begin{document}



\testinitial{\name}{Whoo hoo!}{Not whoo hoo.}

\testinitial{\othername}{Whoo hoo!}{Not whoo hoo.}

\end{document}

enter image description here

1
  • @AdamErickson: You're welcome – user31729 Jan 14 '19 at 16:31
0

Thank you, @Werner and @ChristianHupfer! Based on your solutions, I've found another solution using xstring that appears quite clean:

\documentclass{article}

\usepackage{xstring}

\newcommand{\name}{John Doe}

\makeatletter

\newcommand{\middleinitial}{%
  \StrBetween{\name}{ }{.}[\@middleinitial]%
}

\newcommand{\test}{%
  \middleinitial % Find middle initial
  \IfStrEq{\@middleinitial}{}%
    {Whoo hoo!}%
    {Not whoo hoo.}%
}

\makeatother

\begin{document}

  \test % Whoo hoo.

  \renewcommand{\name}{John F. Doe}%

  \test % Not whoo hoo!

\end{document}

I've posted a follow-up question with a more vexing expansion problem related to \IfStrEqual and \IfSubStr here (link) if anyone can help.

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.