Interaction of \left and \right with \ifthenelse

Purpose

I want a function that surrounds an expression in \left and \right brackets, where the shape of the bracket is given as a parameter, e.g.

\brackets[(][]]{\frac{1}{2}} % should return \left(\frac{1}{2}\right]


I'd also like the function to detect the shape of the opening bracket and supply the matching closing bracket unless told otherwise.

Background

If you want the gory details, I have actually made such a function, and it looks like this:

\usepackage{amsmath,xargs,xifthen}
\newcommandx{\brackets}[3][1=r, 2=default]{
\ifthenelse{\equal{#1}{r}}{ % r for round bracket
\ifthenelse{\equal{#2}{default}}{\left(#3\right)}{}
\ifthenelse{\equal{#2}{r}}{\left(#3\right)}{}
\ifthenelse{\equal{#2}{s}}{\left(#3\right]}{}
\ifthenelse{\equal{#2}{c}}{\left(#3\right\}}{}
\ifthenelse{\equal{#2}{v}}{\left(#3\right|}{}
\ifthenelse{\equal{#2}{}}{\left(#3\right.}{}
}{}
\ifthenelse{\equal{#1}{s}}{ % s for square bracket
\ifthenelse{\equal{#2}{default}}{\left[#3\right]}{}
\ifthenelse{\equal{#2}{r}}{\left[#3\right)}{}
\ifthenelse{\equal{#2}{s}}{\left[#3\right]}{}
\ifthenelse{\equal{#2}{c}}{\left[#3\right\}}{}
\ifthenelse{\equal{#2}{v}}{\left[#3\right|}{}
\ifthenelse{\equal{#2}{}}{\left[#3\right.}{}
}{}
\ifthenelse{\equal{#1}{c}}{ % c for curly brace
\ifthenelse{\equal{#2}{default}}{\left\{#3\right\}}{}
\ifthenelse{\equal{#2}{r}}{\left\{#3\right)}{}
\ifthenelse{\equal{#2}{s}}{\left\{#3\right]}{}
\ifthenelse{\equal{#2}{c}}{\left\{#3\right\}}{}
\ifthenelse{\equal{#2}{v}}{\left\{#3\right|}{}
\ifthenelse{\equal{#2}{}}{\left\{#3\right.}{}
}{}
\ifthenelse{\equal{#1}{v}}{ % v for vertical bar
\ifthenelse{\equal{#2}{default}}{\left|#3\right|}{}
\ifthenelse{\equal{#2}{r}}{\left|#3\right)}{}
\ifthenelse{\equal{#2}{s}}{\left|#3\right]}{}
\ifthenelse{\equal{#2}{c}}{\left|#3\right\}}{}
\ifthenelse{\equal{#2}{v}}{\left|#3\right|}{}
\ifthenelse{\equal{#2}{}}{\left|#3\right.}{}
}{}
\ifthenelse{\equal{#1}{}}{
\ifthenelse{\equal{#2}{default}}{#3}{}
\ifthenelse{\equal{#2}{r}}{\left.#3\right)}{}
\ifthenelse{\equal{#2}{s}}{\left.#3\right]}{}
\ifthenelse{\equal{#2}{c}}{\left.#3\right\}}{}
\ifthenelse{\equal{#2}{v}}{\left.#3\right|}{}
\ifthenelse{\equal{#2}{}}{\left.#3\right.}{}
}{}
}


I suspect this could be much shorter.

Problem

I seem to run into difficulty when I try to write an auxiliary function to detect the opening bracket and supply the matched closing bracket:

\newcommand{\partner}[1]{%
\ifthenelse{\equal{#1}{.}}{.}{}%
\ifthenelse{\equal{#1}{(}}{)}{}%
\ifthenelse{\equal{#1}{)}}{(}{}%
\ifthenelse{\equal{#1}{[}}{]}{}%
\ifthenelse{\equal{#1}{]}}{[}{}%
\ifthenelse{\equal{#1}{\{}}{\}}{}%
\ifthenelse{\equal{#1}{\}}}{\{}{}%
}


There seems to be an awkward interaction between \left/\right and ifthenelse.

Minimal example of problem

\documentclass{article}
\usepackage{amsmath,xifthen}

\newcommand{\funcA}{
)
}
\newcommand{\funcB}{
\ifthenelse{1=1}{)}{}
}

\begin{document}
\begin{align*}
\csname left\endcsname(\frac{1}{2}\csname right\endcsname\funcA \\ % works
\csname left\endcsname(\frac{1}{2}\csname right\endcsname\funcB % doesn't work
\end{align*}
\end{document}

• Probably not the issue, but your macro call should probably be \brackets[(][{]}]{\frac{1}{2}} to keep the ] from messing up the optional argument parsing – Don Hosek Apr 4 at 3:58
• Is there any reason for using \csname...\endcsname? – egreg Apr 4 at 13:34

1. you should not use indiscriminately \left and \right for several reasons;
2. typing (a+b) is much easier than \brackets{a+b}.

I used the standard abbreviation for delimiters as used by amsmath.

\documentclass{article}

\ExplSyntaxOn
\NewDocumentCommand{\brackets}{O{p}O{#1}m}
{
\left
\str_case:nnF { #1 } { {p}{(} {b}{[} {B}{\{} {v}{|} {V}{\|} {.}{.} } {.}
#3
\right
\str_case:nnF { #2 } { {p}{)} {b}{]} {B}{\}} {v}{|} {V}{\|} {.}{.} } {.}
}
\ExplSyntaxOff

\begin{document}

$\brackets{a+b}$
$\brackets[b]{a+b}$
$\brackets[b][p]{a+b}$
$\brackets[B]{a+b}$
$\brackets[v]{a+b}$
$\brackets[V]{a+b}$
$\brackets[?]{a+b}$

\end{document}


The command has two optional argument: the default of the first one is p (parentheses, round brackets); the default for the second one is “the same as the first optional argument”.

In case one or both are not among the defined abbreviations, the empty delimiter is returned (so you can also use \brackets[.]{a+b}, by the way).

One might also add a warning/error message in case of no match.

What's the problem with \ifthenelse? That \left and \right do macro expansion in order to find a suitable delimiter (either a character with nonnegative \delcode or the primitive \delimiter), but \ifthenelse does not simply return the true or false branch as it doesn't work by pure expansion and does assignments.

To the contrary, \str_case:nnF works by pure expansion.

Perhaps this isn't quite what you asked, but here, \brackets either takes no arguments, giving default () brackets, or else you provide two tokens after \brackets for the tokens. Additionally, optional space is permitted before and after the two bracket tokens.

The problem with optional arguments, as Don noted in a comment is that brackets inside of optional arguments are tricky.

\documentclass{article}
\def\brackets{\futurelet\z\brakA}
\def\brakA{\ifx\bgroup\z\expandafter\brakC
\else\expandafter\brakB\fi}
\def\brakB#1#2{\brakD{#1}{#2}}
\def\brakC{\brakD{(}{)}}
\newcommand\brakD[3]{\left#1#3\right#2}
\begin{document}\noindent
$\brackets {\frac{x}{2}}$\\
$\brackets [) {\frac{x}{2}}$\\
$\brackets \{\} {\frac{x}{2}}$\\
$\brackets (\} {\frac{x}{2}}$\\
$\brackets (. {\frac{x}{2}}$\\
\end{document}


SUPPLEMENT

Here is a more complex version that allows also a single delimiter to be supplied, where the 2nd (missing) one is implied. As before, optional space is permitted before and after the two bracket tokens, but in this case, not between them.

\documentclass{article}
\usepackage{etoolbox}
\csdef{brak[}{]}
\csdef{brak(}{)}
\csdef{brak\string\{}{\}}
\csdef{brak.}{.}
\def\brackets{\futurelet\z\brakA}
\def\brakA{\ifx\bgroup\z\expandafter\brakC
\else\expandafter\brakB\fi}
\def\brakB#1{\def\zz{#1}\futurelet\zzz\brakD}
\def\brakC{\brakF()}
\makeatletter
\def\brakD{%
\edef\zzzz{\csname brak\expandafter\string\zz\endcsname}%
\ifx\bgroup\zzz\def\next{\zzzz}\else
\ifx\@sptoken\zzz\def\next{\zzzz}\else
\def\next{}\fi\fi\expandafter\brakE\next}
\makeatother
\def\brakE#1{\brakF\zz#1}
\newcommand\brakF[3]{\left#1#3\right#2}
\begin{document}\noindent
No Delimiter\\
$\brackets {\frac{x}{2}}$\\
One Delimiter:\\
$\brackets ( {\frac{x}{2}}$\\
$\brackets [ {\frac{x}{2}}$\\
$\brackets \{ {\frac{x}{2}}$\\
$\brackets . {\frac{x}{2}}$\\
Two Delimiters:\\
$\brackets [) {\frac{x}{2}}$\\
$\brackets \{) {\frac{x}{2}}$\\
$\brackets (\} {\frac{x}{2}}$\\
$\brackets (. {\frac{x}{2}}$\\
\end{document}