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?

  • @Werner I've opened a new question here: https://tex.stackexchange.com/questions/470467/use-xstring-to-substitute-reformatted-names-in-strings – Adam Erickson Jan 17 '19 at 00:45
  • @ChristianHupfer I've opened a new question here: https://tex.stackexchange.com/questions/470467/use-xstring-to-substitute-reformatted-names-in-strings – Adam Erickson Jan 17 '19 at 00:45

3 Answers3

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}
Werner
  • 603,163
  • What is this monstrosity: \expandafter\if\expandafter\relax\expandafter\detokenize\expandafter{\@middleinitial}\relax? – Adam Erickson Jan 13 '19 at 06: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
  • Question: how can I use the output of a command callingmiddleinitial in IfSubStr? Currently, it does not correctly match strings. – Adam Erickson Jan 14 '19 at 21:31
  • @AdamErickson: Can you provide an example? Perhaps posting the code on Pastebin? – Werner Jan 14 '19 at 21:37
  • Updated: https://pastebin.com/JqSZWMQU The \surnamefirst and \surnamelast commands work as expected in tests in terms of string output. Also, \StrSubstitute works when using raw string inputs. – Adam Erickson Jan 14 '19 at 21:54
  • @AdamErickson: That paste has been removed...? – Werner Jan 14 '19 at 23:14
  • This one will remain longer: https://pastebin.com/hb1U1zCa – Adam Erickson Jan 14 '19 at 23:25
  • @AdamErickson: Can you provide a complete example? Something that starts with \documentclass and ends with \end{document}? Also, avoid using \middle for your middle initial storage; it's already defined within the context of \left...\middle...\right... – Werner Jan 15 '19 at 01:00
  • Edited: Here is a complete example: https://pastebin.com/aF9gKsz7. What should happen is that the \name should be reformatted to the citation style, matched in the bibliography, and substituted with bold text. – Adam Erickson Jan 15 '19 at 02:15
  • @AdamErickson: Under \bibliographystyle{plainnat}, \bibitem is defined to be \bibitem[<title>]{<label>}. Your redefinition using \def\bibitem#1#2{...} does not take the optional argument into account, leading to problems. – Werner Jan 15 '19 at 04:17
  • Sorry, I am a bit new to this. How should it be implemented? It was not throwing an error for me. Here, it says that this would simply generate a number (http://www.stat.unipg.it/tex-man/ltx-205.html). – Adam Erickson Jan 15 '19 at 04:31
  • @AdamErickson: So all you want is for the author titles to be bold? – Werner Jan 15 '19 at 05:26
  • Yes, just for the single author name (e.g., William Fulton). So, where it shows up as W. Fulton or Fulton, W. it should be made bold. – Adam Erickson Jan 15 '19 at 17:05
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

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.