5

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.

5
  • Is "list" always going to be defined as a comma-separated collection of strings?
    – Mico
    Aug 11, 2015 at 16:20
  • Probably. I think it is somehow natural, while {}{}{}..., for instance, is not.
    – ASdeL
    Aug 11, 2015 at 16:29
  • 1
    you don't need a package \in@ and \ifin@ are predefined in the latex format. Aug 11, 2015 at 16:36
  • @David: Thanks. This is interesting. Should I use makeatletter/makeatother?. I would like a plain simple command.
    – ASdeL
    Aug 11, 2015 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. Aug 11, 2015 at 16:54

5 Answers 5

4

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}
2
  • 4
    I'm not convinced with this. I do not like that \IfSubStr{George,John,Paul,Ringo}{ul,Ri}{True}{False} is True.
    – ASdeL
    Aug 11, 2015 at 16:17
  • 2
    Good recovery. +1 Aug 11, 2015 at 18:46
7

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.

4
  • Odd I didn't see this but system says you posted a minute ahead of me, I'll delete mine:-) Aug 11, 2015 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, 2015 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, 2015 at 17:20
  • @clemens: See my edit in the question. Thanks.
    – ASdeL
    Aug 11, 2015 at 21:35
3

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}
1

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} 
1
  • Thank you, but I am looking for an already defined command \IfStringInList (or any other name) in a common package.
    – ASdeL
    Aug 11, 2015 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}
1
  • Thank you, but I am looking for an already defined command \IfStringInList (or any other name) in a common package.
    – ASdeL
    Aug 11, 2015 at 16:42

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.