# Conditional with multiple conditions, one of which is a string search

Aim

I want a command to write "where #1 is an arbitrary constant", "where #1 are arbitrary constants", "where #1 is an arbitrary function of #2", or "where #1 are arbitrary functions of #2", as appropriate.

Background

Usually it's enough to let singular-plural detection rely on the presence or absence of a comma in #1. For that, the following function works fine.

\documentclass{article}
\usepackage{xstring,xargs,xifthen,amsmath}
\newcommandx{\arbitrary}[3][1=\text{ where }, 3=]{%
#1#2%
\IfSubStr{#2}{,}{\text{ are}}{\text{ is an}}%
\text{ arbitrary}%
\ifthenelse{\equal{#3}{}}{\text{ constant}}{\text{ function}}%
\IfSubStr{#2}{,}{\text{s}}{}%
\ifthenelse{\equal{#3}{}}{}{\text{ of }#3}
}
\begin{document}
\begin{align*}
& \arbitrary{a} \\ % where a is an arbitrary constant
& \arbitrary{a,b} \\ % where a,b are arbitrary constants
& \arbitrary{f}[x] \\ % where f is an arbitrary function of x
& \arbitrary{f,g}[x] % where f,g are arbitrary functions of x
\end{align*}
\end{document}


But sometimes I want to pluralise a singular-looking argument, like

2a_n+1, \text{ where $a_n$ are arbitrary constants, } n \in \{1,2,\dots\}


For this I'm trying to implement a backup detection mechanism, using an optional argument. This involves defining two conditions on which the function will treat #1 as plural: if #1 contains a comma, or if #4=p for plural.

\documentclass{article}
\usepackage{xstring,xargs,xifthen}
\newcommandx{\arbitrary}[4][1=\text{ where }, 3=, 4=]{%
#1#2%
\ifthenelse{%
1=\IfSubStr{#2}{,}{1}{0}\OR%
\equal{#4}{p}%
}{\text{ are}}{\text{ is}}%
\text{ arbitrary}%
\ifthenelse{\equal{#3}{}}{\text{ constant}}{\text{ function}}%
\ifthenelse{%
1=\IfSubStr{#2}{,}{1}{0}\OR%
\equal{#4}{p}%
}{\text{s}}{}%
\ifthenelse{\equal{#3}{}}{}{\text{ of }#3}
}
\begin{document}
I wish this function worked.
\end{document}


Problem

LaTeX seems not to like the syntax \ifthenelse{1=\IfSubStr{ab}{a}{1}{0}}{1}{0}.

\documentclass{article}
\usepackage{xstring,xifthen}
\begin{document}
\IfSubStr{ab}{a}{1}{0} % returns 1
\ifthenelse{1=1}{1}{0} % returns 1
\ifthenelse{1=\IfSubStr{ab}{a}{1}{0}}{1}{0} % returns error
\end{document}


An extended version that also copes with multivariate functions. The *-version forces plural.

\documentclass{article}
\usepackage{amsmath}

\ExplSyntaxOn

\NewDocumentCommand{\arbitrary}{smo}
{% #1 = boolean for forcing plural
% #2 = mandatory argument
% #3 = optional argument for the variable
\IfBooleanTF{#1}
{ \bool_set_true:N \l_mjc_arbitrary_plural_bool }
{ \bool_set_false:N \l_mjc_arbitrary_plural_bool }
\IfNoValueTF{#3}
{ \mjc_arbitrary_constant:n { #2 } }
{ \mjc_arbitrary_function:nn { #2 } { #3 } }
}

\bool_new:N \l_mjc_arbitrary_plural_bool
\seq_new:N \l__mjc_arbitrary_variables_seq
\seq_new:N \l__mjc_arbitrary_variables_out_seq

\cs_new_protected:Nn \mjc_arbitrary_constant:n
{
\bool_lazy_or:nnTF
{ \l_mjc_arbitrary_plural_bool }
{ \int_compare_p:n { \clist_count:n { #1 } > 1 } }
{ \mjc_arbitrary_phrases:nnnn { #1 } { are } { constants } { } }
{ \mjc_arbitrary_phrases:nnnn { #1 } { is~an } { constant } { } }
}

\cs_new_protected:Nn \mjc_arbitrary_function:nn
{
\bool_lazy_or:nnTF
{ \l_mjc_arbitrary_plural_bool }
{ \int_compare_p:n { \clist_count:n { #1 } > 1 } }
{ \mjc_arbitrary_phrases:nnnn { #1 } { are } { functions } { #2 } }
{ \mjc_arbitrary_phrases:nnnn { #1 } { is~an } { functions } { #2 } }
}

\cs_new_protected:Nn \mjc_arbitrary_phrases:nnnn
{% #1 = object, #2 = verb, #3 = type, #4 = optional variable
\mode_if_math:TF
{ \text { \__mjc_arbitrary_phrases:nnnn { #1 } { #2 } { #3 } { #4 } } }
{ \__mjc_arbitrary_phrases:nnnn { #1 } { #2 } { #3 } { #4 } }
}
\cs_new_protected:Nn \__mjc_arbitrary_phrases:nnnn
{
where~$#1$~#2~arbitrary~#3
\tl_if_blank:nF { #4 }
{
\seq_set_from_clist:Nn \l__mjc_arbitrary_variables_seq { #4 }
\c_space_tl of~the~variable
\int_compare:nT { \seq_count:N \l__mjc_arbitrary_variables_seq > 1 } { s }
\nobreakspace
\__mjc_arbitrary_variables:
}
}
\cs_new_protected:Nn \__mjc_arbitrary_variables:
{
\seq_set_map:NNn \l__mjc_arbitrary_variables_out_seq \l__mjc_arbitrary_variables_seq { $##1$ }
\seq_use:Nnnn \l__mjc_arbitrary_variables_out_seq { ~and~ } { ,~ } { ,~and\nobreakspace }
}
\ExplSyntaxOff

\begin{document}

\begin{align*}
& \arbitrary{a} \\ % where a is an arbitrary constant
& \arbitrary*{a_n} \\ % where a_n are arbitrary constants
& \arbitrary{a,b} \\ % where a,b are arbitrary constants
& \arbitrary{f}[x] \\ % where f is an arbitrary function of x
& \arbitrary{f,g}[x] \\% where f,g are arbitrary functions of x
& \arbitrary{f}[x,y] \\ % where f is an arbitrary function of x and y
& \arbitrary{f,g}[x,y] \\% where f,g are arbitrary functions of x, y, and z
& \arbitrary*{f_n}[x] \\ % where f is an arbitrary function of x
& \arbitrary*{f_n}[x,y] % where f is an arbitrary function of x and y
\end{align*}

\arbitrary{a},
\arbitrary*{a_n},
\arbitrary{a,b},
\arbitrary{f}[x],
\arbitrary{f,g}[x],
\arbitrary*{f_n}[x].

\end{document}


I only use \text if the command is found in math mode; in text mode you don't want to make the thing unbreakable across lines.

Slight complication is using ~ where you want a space, but it just requires a bit of practice.

I use etoolbox to condition on the presence of , within your first argument (via \patchcmd{<cmd>}{<search>}{<replace>}{<success>}{<failure>}). That provides the first conditional branch. Then I condition on the existence of a closing optional argument using xparse's \IfValueTF{<arg>}{<true>}{<false>}.

\documentclass{article}

% \usepackage{xparse}% Only if you have LaTeX < 2020-10
\usepackage{etoolbox,amsmath}

\NewDocumentCommand{\arbitrary}{m o}{
\def\firstarg{#1}% Store mandatory argument
\text{ where }
\firstarg
\IfValueTF{#2}
{\patchcmd{\firstarg}{,}{,}
{\text{ are arbitrary functions of } #2}% Contains a comma , => plural
{\text{ is an arbitrary function of } #2}}% Does not contain a comma , => singular
{\patchcmd{\firstarg}{,}{,}
{\text{ are arbitrary constants}}% Contains a comma , => plural
{\text{ is an arbitrary constant}}}% Does not contain a comma , => singular
}
\begin{document}

\begin{align*}
& \arbitrary{a} \\ % where a is an arbitrary constant
& \arbitrary{a,b} \\ % where a,b are arbitrary constants
& \arbitrary{f}[x] \\ % where f is an arbitrary function of x
& \arbitrary{f,g}[x] % where f,g are arbitrary functions of x
\end{align*}

\end{document}


If you want to force a plural output for a singular item, you could adapt \arbitrary to take a star - \arbitrary*. This is how you'd condition using that:

\documentclass{article}

% \usepackage{xparse}% Only if you have LaTeX < 2020-10
\usepackage{etoolbox,amsmath}

\NewDocumentCommand{\arbitrary}{s m o}{
\def\firstarg{#2}% Store mandatory argument
\text{ where }
\firstarg
\IfBooleanTF{#1}
{\text{ are arbitrary constants}}% Starred version => plural
{
\IfValueTF{#3}
{\patchcmd{\firstarg}{,}{,}
{\text{ are arbitrary functions of } #3}% Contains a comma , => plural
{\text{ is an arbitrary function of } #3}}% Does not contain a comma , => singular
{\patchcmd{\firstarg}{,}{,}
{\text{ are arbitrary constants}}% Contains a comma , => plural
{\text{ is an arbitrary constant}}}% Does not contain a comma , => singular
}
}
\begin{document}

\begin{align*}
& \arbitrary{a} \\ % where a is an arbitrary constant
& \arbitrary*{a_n} \\ % where a_n are arbitrary constants
& \arbitrary{a,b} \\ % where a,b are arbitrary constants
& \arbitrary{f}[x] \\ % where f is an arbitrary function of x
& \arbitrary{f,g}[x] % where f,g are arbitrary functions of x
\end{align*}

\end{document}

• This seems to replicate the functionality of the original command, but does it handle the exception I described? If my original syntax had worked, I would have written \arbitrary{a_n}[][p] and got "where $a_n$ are arbitrary constants". Could you clarify how I can do that with your command?
– mjc
Apr 8 at 4:08
• @mjc: Sure it does. You should try it! The only thing that distinguishes between singular or plural usage is a , (comma) in the first/mandatory argument. Since a_n doesn't have a ,, it's considered singular. Note though that it won't work if you pass a macro that has your list of items in there (for example, \newcommand{\itemlist}{a_n, b_n} and then use \arbitrary{\itemlist} will print a singular phrase). Apr 8 at 4:59
• "Since a_n doesn't have a , it's considered singular.". Right; that's the problem that motivated the OP. I want the option to treat singular-looking expressions like a_n as plural.
– mjc
Apr 8 at 5:02
• @mjc - You wrote, "I want the option to treat singular-looking expressions like a_n as plural." Do your readers somehow know that a_n is a plural object even though it sure looks like a singular object?
– Mico
Apr 8 at 5:42
• @mjc: How about this as an option? For the odd case you want to force as plural, use \arbitrary*{a_n}. Apr 8 at 14:47