# Detect if a macro argument is only one symbol

I define a bunch of functions (or operators, if you like) using a little helper \parens, which adds parens on demand:

\newcommand{\parens}[1]{
\ifthenelse{\equal{#1}{}}{}{(#1)}
}

\newcommand{\fv}[1]{\text{fv}\parens{#1}}


This way, I can write \fv{e} for “fv(e)”, but also write \fv{} \colon Expr \to Var to obtain “fv : Expr → Var”.

On paper, I would usually omit the parentheses if the argument is a single symbol, i.e. fv e, but still fv (e₁ e₂).

How would I beef up my \parens macro to avoid adding the parentheses if the argument evaluates to a single symbol?

It does not have to be perfect and may err on the side of adding unnecessary parentheses.

Here is a MWE to play around with:

\documentclass{article}
\usepackage{amsmath}
\usepackage{ifthen}

\newcommand{\parens}[1]{
\ifthenelse{\equal{#1}{}}{}{(#1)}
}
\newcommand{\fv}[1]{\text{fv}\parens{#1}}

\begin{document}
Has no parentheses: $\fv{}$.

Should have no parentheses: $\fv{e}$, $\fv{\alpha}$.

Should have parentheses: $\fv{e_1 + e_2}$, $\fv{e_1+e_2}$, $\fv{e_1, e_2, \ldots}$.

These also could have no parentheses: $\fv{e_1}$
(but that is probably too much to ask)

\end{document}

• Please help us help you and add a minimal working example (MWE) that illustrates your problem. Reproducing the problem and finding out what the issue is will be much easier when we see compilable code, starting with \documentclass{...} and ending with \end{document}. – user31729 Jul 20 '15 at 13:41
• Package xstring can check for white space – user31729 Jul 20 '15 at 13:48
• How about defining a starred version of \fv which omits the parentheses either way? – clemens Jul 20 '15 at 14:00
• I’d like to make that choice automatic, so that the style is consistent across a large document, and that I can easily switch between them. – Joachim Breitner Jul 20 '15 at 14:03
• Just to clarify: what is the advantage in using this approach? IMOP it is the same as \fv(e) or \fv\colon A\to B. You have to type the braces, so why not type the parenthesis? – Sigur Jul 20 '15 at 18:43

You can do it with regular expression, after checking the argument is blank: if the argument matches just a token or a token followed by a _ and a subscript, then use no parentheses.

\documentclass{article}
\usepackage{amsmath}
\usepackage{expl3,xparse,l3regex}

\DeclareMathOperator{\fvop}{fv}

\ExplSyntaxOn

\NewDocumentCommand{\fv}{m}
{
\fvop
\tl_if_blank:nF { #1 }
{
\regex_match:nnTF { \A . ( \_. | \_\{.*?\} )? \Z } { #1 }
{
#1
}
{
(#1)
}
}
}

\ExplSyntaxOff

\begin{document}

Has no parentheses: $\fv{}$.

Has no parentheses: $\fv{e_1}$.

Should have no parentheses: $\fv{e}$, $\fv{\alpha}$, $\fv{\alpha_{12}}$.

Should have parentheses: $\fv{e+f}$, $\fv{\alpha+\beta}$.

Should have parentheses: $\fv{e+f}$, $\fv{\alpha+\beta}$.

Should have parentheses: $\fv{e_1 + e_2}$, $\fv{e_1+e_2}$, $\fv{e_1, e_2, \ldots}$.

\end{document}


An extended version where \fv*{...} forces automatically extendable parentheses, while \fv[\big]{...} uses a bigger version if the argument is not a single variable (you can also use \Big, \bigg or \Bigg).

• Fancy! It does’t feel right to apply a regex to the Code of the argument, when morally the condition applies to the result of the argument, but from a practical point of view it is great. – Joachim Breitner Jul 20 '15 at 19:19

The concept of “single symbol” is somewhat vague: I can suggest an exact test as to whether the argument is, or is not, a single token.

\documentclass{article}

\makeatletter

\newcommand*\IsOnlyOneToken[1]{%
TT\fi
\@IsOnlyOneToken#1\@@@
}
\@ifdefinable\@IsOnlyOneToken{\def\@IsOnlyOneToken#1#2\@@@{%
\ifx\@empty#2\@empty
}}

\makeatother

\newcommand*{\clientCommand}[1]{%
\mathrm{fv}%
\if\IsOnlyOneToken{#1}%
\,#1%
\else
\left(#1\right)%
\fi
}

\begin{document}

Single token:
$\clientCommand{x}$,
$\clientCommand{\alpha}$.

Multiple tokens:
$\clientCommand{x+1}$,
$\clientCommand{x_{1}}$.

But an override is available:
$\clientCommand{{x_{1}}}$.

\end{document}


Here is the output (it is not much important, however: you need to try yourself…):

As you see, the test treats the argument as a single token if you enclose it with an additional pair of braces. I regard this as a feature, not as a bug.

EDIT

The above code will break down if \IsOnlyOneToken is invoked with an empty argument, that is, an argument containing zero tokens. Here is a fix:

\documentclass{article}

\makeatletter

\newcommand*\IsExactlyOneToken[1]{%
TT\fi
\ifx\@empty#1\@empty
\expandafter\@EmptyCase
\else
\expandafter\@IsOnlyOneToken
\fi
#1\@@@
}
\@ifdefinable\@IsOnlyOneToken{\def\@IsOnlyOneToken#1#2\@@@{%
\ifx\@empty#2\@empty
}}
\@ifdefinable\@EmptyCase{\def\@EmptyCase#1\@@@{% #1 for robustness
\iffalse % since 0 != 1
}}

\makeatother

\newcommand*{\clientCommand}[1]{%
\mathrm{fv}%
\if\IsExactlyOneToken{#1}%
\,#1%
\else
\nonscript\!\left(#1\right)%
\fi
}

\begin{document}

Single token:
$\clientCommand{x}$,
$\clientCommand{\alpha}$.

Multiple tokens:
$\clientCommand{x+1}$,
$\clientCommand{x_{1}}$.

But an override is available:
$\clientCommand{{x_{1}}}$.

The bug has been corrected:
$\clientCommand{}$\ldots

\makeatletter
\ldots also for pathological'' cases:
$\clientCommand\@empty$, $\clientCommand{\@empty}$.
Override: $\clientCommand{{\@empty}}$.
\makeatother

\end{document}


Output:

• That might also be quite a viable solution, if the logic is kept in mind while using the such defined command. thanks! – Joachim Breitner Jul 20 '15 at 18:28
• @egreg: Admittedly, this solution fails if the argument is empty… :-) – GuM Jul 20 '15 at 18:39
• BTW, is this implementation of a custom argument to \if idiomatic? I see it the first time now, and it looks very hackish, if not downright evil. :-) – Joachim Breitner Jul 20 '15 at 19:21
• @JoachimBreitner: Yes, it is. It is not exactly an argument to \if, however, but a consequence of the general rule that tokens after \if are expanded. It permits you to have an explicit \if to go with \else and \fi, for the case in which text is being skipped over. – GuM Jul 20 '15 at 19:29
• I’m using this for now and see how well it goes. – Joachim Breitner Jul 22 '15 at 9:11

The \IfSubStr macro from xstring can look for white space characters (well, blanks) between a string. However, this is not failsafe.

\documentclass{article}

\usepackage{xstring}
\usepackage{ifthen}
\usepackage{mathtools}

\newcommand{\parens}[1]{
\ifthenelse{\equal{#1}{}}{}{(#1)}
}

\newcommand{\myarg}{e_{1} e_{2}}

\newcommand{\myotherarg}{e_{1} }

\newcommand{\fv}[1]{\text{fv}%
\IfSubStr{#1}{ }{%
\parens{#1}
}{\,#1}
}

\begin{document}
$\fv{v}$

$\fv{e_{1} e_{2}}$

$\fv{\myarg}$
$\fv{\myotherarg}$

\end{document}

• Interesting idea to simply look for whitespace. It would not work in the case of \fv{e_1+e_2}, but I could probably avoid not putting a space in complex arguments. – Joachim Breitner Jul 20 '15 at 13:51
• @JoachimBreitner: Yes, that's true, and that's why I am looking for a better way – user31729 Jul 20 '15 at 13:53
• Also, I get TeX capacity exceeded, sorry [input stack size=5000]. if the argument is \textlambda with \usepackage[safe]{tipa} enabled. – Joachim Breitner Jul 20 '15 at 13:58
• @JoachimBreitner: Well, is tipa in your MWE? ;-) – user31729 Jul 20 '15 at 14:01
• No, of course not :-). Looks like xstring has more problems with my stuff, including breaking on arguments containing \phantom. – Joachim Breitner Jul 20 '15 at 14:02

With xstring package you can retrieve the length of a string:

\documentclass{article}
\usepackage{xstring}
\usepackage{ifthen}
\newcommand\fv[1]{%
fv~%
\ifthenelse{\equal{#1}{}}{}{%
\StrLen{#1}[\mylen]%
\ifthenelse{\equal{\mylen}{1}}{#1}{(#1)}%
}%
}

\begin{document}
\fv{e}\par
\fv{e1 e2}

\end{document}

• The length of the string does not say if it's just one symbol or a bunch of them – user31729 Jul 20 '15 at 13:52
• Would that work with \fv{\alpha}? – Joachim Breitner Jul 20 '15 at 13:53
• I'm not sure about the interns of xstring, but it should work with any characters, \alpha works too. \fv{e1} won't work and needs more conditionals – musicman Jul 20 '15 at 13:56