7

Is there a package that provides a command for testing whether a string is in a list? I saw several answers that define their own commands to perform this or similar tasks, but I prefer a "self-evolving", and well-documented solution for this kind of tasks. More precisely, the command should be something like this

\IfStringInList{string}{list}{DoThisIfTrue}{DoThisIfFalse}

For instance

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

EDIT: I'm not against defining commands. I expected thas this natural functionality was present in a ready-to-use package, that can be accessed in a very simple way.

ASdeL
  • 4,925
  • Is "list" always going to be defined as a comma-separated collection of strings? – Mico Aug 11 '15 at 16:20
  • Probably. I think it is somehow natural, while {}{}{}..., for instance, is not. – ASdeL Aug 11 '15 at 16:29
  • 1
    you don't need a package \in@ and \ifin@ are predefined in the latex format. – David Carlisle Aug 11 '15 at 16:36
  • @David: Thanks. This is interesting. Should I use makeatletter/makeatother?. I would like a plain simple command. – ASdeL Aug 11 '15 at 16:49
  • @ASdeL you need something to access commands with @ but see Heiko's answer which is the same as mine (which I have now deleted) but just packaged for actual use. – David Carlisle Aug 11 '15 at 16:54

5 Answers5

11

Simple LaTeX with the kernel command \in@:

\documentclass{article}

\makeatletter
\newcommand*{\IfStringInList}[2]{%
  \in@{,#1,}{,#2,}%
  \ifin@
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
}
\makeatother

\begin{document}
\IfStringInList{Paul}{George,John,Paul,Ringo}{Beat it}{Roll it}
\end{document}

Manual solution without defining a command and without \makeatletter

As requested by the comment. I do not see a sense, not to define a macro.

\csname in@\endcsname{,Paul,}{,George,John,Paul,Ringo,}%
\expandafter\ifx\csname ifin@\expandafter\endcsname\csname iftrue\endcsname
  Beat it%
\else
  Roll it%
\fi

}

The lengthy replacement for \ifin@ is needed, when this construct is inside another \if branch.

Heiko Oberdiek
  • 271,626
  • Odd I didn't see this but system says you posted a minute ahead of me, I'll delete mine:-) – David Carlisle Aug 11 '15 at 16:52
  • @Heiko: Nice answer, but you are still defining your own command. Off course, the command can be removed, but then makeat... must be used between begin/end{document}. – ASdeL Aug 11 '15 at 17:13
  • 1
    @ASdeL what's to say against defining a command? (If you insist you can put the code in a package of your own and – voila – you have a package which provides the command that you want…) – cgnieder Aug 11 '15 at 17:20
  • @clemens: See my edit in the question. Thanks. – ASdeL Aug 11 '15 at 21:35
6

The xtring package provides such command:

\documentclass{article}
\usepackage{xstring}
\newcommand\IfStringInList[2]{\IfSubStr{,#2,}{,#1,}}
\begin{document}
\IfStringInList{Paul}{George,John,Paul,Ringo}{True}{False}

\IfStringInList{Joe}{George,John,Paul,Ringo}{True}{False}

\IfStringInList{ul,Ri}{George,John,Paul,Ringo}{True}{False}
\end{document}
unbonpetit
  • 6,190
  • 1
  • 20
  • 26
4

expl3 has this ready for use: \clist_if_in:nnTF {<clist>} {<item>} {<true>} {<false>}:

\documentclass{article}
\usepackage{expl3,xparse}
\ExplSyntaxOn
\NewDocumentCommand \IfStringInList {mmmm}
  { \clist_if_in:nnTF {#2} {#1} {#3} {#4} }
\ExplSyntaxOff
\begin{document}
\IfStringInList{Paul}{George,John,Paul,Ringo}{Beat it}{Roll it}% Beat it

\IfStringInList{ul,Ri}{George,John,Paul,Ringo}{Beat it}{Roll it}% Roll it
\end{document}
cgnieder
  • 66,645
2

Here's a LuaLaTeX-based solution. It sets up a macro called \IfStringInList and implements it via a call to the Lua function string.find to set up "true" and "false" branches. Observe that both the target string and the search string can be quite general; in particular, the target string need not be a comma-separated collection of strings.

% !TEX TS-program = lualatex
\documentclass{article}
\usepackage{luacode} % for "\luastring" macro
\newcommand\IfStringInList[4]{%
    \directlua{if string.find(\luastring{#2},\luastring{#1}) then
                  tex.print(\luastring{#3})
               else 
                  tex.print(\luastring{#4})
               end}%
    }
\begin{document}
\IfStringInList{Paul}{George,John,Paul,Ringo}{Beat it}{Roll it}% "Beat it"

\IfStringInList{Mozart}{GeorgeJohnPaulRingo}{Strum It}{Hum it} % "Hum it"

\IfStringInList{George,John,Paul,Ringo}{ul,Ri}{True}{False}    % "False"
\end{document} 
Mico
  • 506,678
  • Thank you, but I am looking for an already defined command \IfStringInList (or any other name) in a common package. – ASdeL Aug 11 '15 at 16:34
1

Another way... EDITED to allow blank fields (A,,B)

\documentclass{article}
\usepackage{ifthen}
\newcommand\IfStringInList[4]{\stringsearch#1:#2,\relax\relax%
  \if T\found#3\else#4\fi}
\def\stringsearch#1:#2,#3\relax{\ifthenelse{\equal{#1}{#2}}{\def\found{T}}{%
  \if\relax#3\relax\def\found{F}\else\stringsearch #1:#3\relax\fi}}
\begin{document}
\IfStringInList{Paul}{George,John,Paul,Ringo}{Beat it}{Roll it}

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

\IfStringInList{Yanni}{George,John,Paul,Ringo}{Beat it}{Roll it}
\end{document}
  • Thank you, but I am looking for an already defined command \IfStringInList (or any other name) in a common package. – ASdeL Aug 11 '15 at 16:42