5

Based on this question, I'd like the following

\newcommand{\word}{Paul}
\newcommand{\butnot}{Joe}
\IfStringInList{\word}{George,John,Paul,Ringo}{Beat it}{Roll it}
\IfStringInList{\butnot}{George,John,Paul,Ringo}{Beat it}{Roll it}

to return Beat it and Roll it.

This has in principle been answered here but only with the help of 2 packages. It should, however, be possible much simpler with the solution here, only that I couldn't figure out how to expand the macro? (Not even with the help of this reference :/ )

2 Answers2

5

Essentially a one liner with expl3:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\IfStringInList}{mmmm}
 {
  \clist_if_in:neTF {#2} {#1} {#3} {#4}
 }
\prg_generate_conditional_variant:Nnn \clist_if_in:nn {ne} {T,F,TF}
\ExplSyntaxOff

\begin{document}

\newcommand{\word}{Paul}
\newcommand{\butnot}{Joe}

\IfStringInList{\word}{George,John,Paul,Ringo}{Beat it}{Roll it}

\IfStringInList{\butnot}{George,John,Paul,Ringo}{Beat it}{Roll it}

\end{document}

With e we force full expansion of the first argument.

enter image description here

By the way, e expansion is a big achievement in TeX Live 2019, available with all TeX engines. Since you're talking of strings, I suppose that the material in the search string is fully expandable to characters.

egreg
  • 1,121,712
3

Like this? You need to make sure that \word and/or \butnot get expanded first. This can also be achieved with some \expandafters but since I am never sure how many of those one needs I use a more mundane but IMHO also more accessible syntax. Of course there are many tools that help you doing the same (but at the very moment of writing this I am fighting a conflict between \tikzexternalize and xparse so I feel this solution might be useful for some who have similar clashes).

\documentclass{article}

\makeatletter
\newcommand*{\IfStringInList}[2]{%
  \in@{,#1,}{,#2,}%
  \ifin@
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
}
\makeatother
\newcommand{\IfStringInListExpandedDo}[4]{%
\edef\tmp{\noexpand\IfStringInList{#1}{#2}{\noexpand\edef\noexpand\tst{1}}{\noexpand\edef\noexpand\tst{0}}}%
\tmp%
\ifnum\tst=1\relax%
#3%
\else%
#4%
\fi}

\begin{document}
\newcommand{\word}{Paul}
\newcommand{\butnot}{Joe}
\IfStringInListExpandedDo{\word}{George,John,Paul,Ringo}{abc \textbf{Beat it}}{cde \textit{Roll it}}
\IfStringInListExpandedDo{\butnot}{George,John,Paul,Ringo}{abc\textbf{Beat it}}{cde \textit{Roll it}}
\end{document}

enter image description here

  • Yes, exactly. I had tried \edef without success. How does that work? What is \tmp needed for? – fuenfundachtzig May 07 '19 at 08:16
  • Hm, this fails if there are macros (e.g. \textbf) in Beat it :( – fuenfundachtzig May 07 '19 at 08:31
  • @fuenfundachtzig This tells LaTeX to first expand \word (or \butnot) and then \IfStringInList. And no, \textbf and so on do not work in this version (but I didn't know that was a requirement). –  May 07 '19 at 13:49
  • Thanks. Not it wasn't an explicit requirement. But is it possible to make this work? – fuenfundachtzig May 07 '19 at 16:35
  • @fuenfundachtzig Yes, sure. \edef\tmp{\noexpand\IfStringInList{\word}{George,John,Paul,Ringo}{\noexpand\textbf{Beat it}}{Roll it} \noexpand\IfStringInList{\butnot}{George,John,Paul,Ringo}{\noexpand\textbf{Beat it}}{Roll it}}% \tmp You need to make sure that these get expanded only in the very end, when \IfStringInList gets expanded. –  May 07 '19 at 16:39
  • @fuenfundachtzig I rewrote my answer in such a way that you can use \textbf and that the code gets shorter. –  May 07 '19 at 16:49
  • Thanks. It's still very fragile, e.g. having additional text before \textbf would now cause it to fail. – fuenfundachtzig May 08 '19 at 20:03
  • @fuenfundachtzig Better now? –  May 09 '19 at 03:48
  • This seems to work perfectly, thanks! – fuenfundachtzig May 09 '19 at 08:47