Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I would like to create a smart parenthesing command without using the xparse package.

\p(1)   prints  (1)
\p[1]           [1]
\p{1}           {1}
\p(1|2)         (1|2)

I tried this code but it doesn't work for braces.
Also, I don't know how to do (1|2).

\documentclass{article}

\makeatletter

\def\p
{
    \@ifnextchar(
        {\@parenthesis}
        {
            \ifx\@let@token[
                \expandafter\@bracket
            \else
                \expandafter\@brace
            \fi
        }
}

\def\@parenthesis(#1){\left( #1 \right)}
\def\@bracket[#1]{\left[ #1 \right]}
\def\@brace#1{\left{ #1 \right}}

\makeatother


\begin{document}

$\p(1)$ 
$\p[1]$ 
$\p{1}$ 
$\p(1|2)$    
\end{document}

My motivation for doing this is to get a more expressive syntax.

share|improve this question
1  
Is there any chance that your expressions will include nested parentheses, brackets, and/or braces? –  Mico Jan 30 '13 at 14:33
3  
@NicolasEssis-Breton Then you've lost; \p(f(2)) won't work with any "reasonable" definition. –  egreg Jan 30 '13 at 14:48
4  
Note that defining such syntax (while possible) is explicitly against the latex syntax guidelines and as other constructs will not be expecting this syntax it's likely to lead to problems when combined with other code tex.stackexchange.com/questions/84685/… –  David Carlisle Jan 30 '13 at 15:14
2  
@NicolasEssis-Breton only {} groups form part of TeX's parsing rules (and are matched according to nesting depth () are just two unrelated characters TeX has no inbuilt knowledge that one is paired with the other and that is useful for notations such as )a,b( –  David Carlisle Jan 30 '13 at 17:04
1  
@NicolasEssis-Breton TeX is a language for typesetting; while braces don't play an important role in typeset text, (round) parentheses do and in many situations they don't come in pairs. Other languages can do differently because they don't have as their main objective typesetting text. –  egreg Jan 30 '13 at 21:19
show 3 more comments

2 Answers 2

up vote 9 down vote accepted

This appears to work:

Update: see further down a different implementation which does the \left and \right things and also is compatible with a \middle in-between.

Second Update: mathcodes do not have all the limitations of catcodes. Based on mathcodes I propose one more approach which is more powerful than the previous one: it allows (seemingly) very complicated nesting. I dream there were textcodes... the point is that mathcodes do not freeze. This is extremely useful.

Edit: correct restores of the mathcodes after some additional work. I promise not to edit again...

\documentclass{article}

\makeatletter

\def\p{\afterassignment\p@aux\let\next=}

\def\p@aux{\ifx\next\bgroup\lbrace\bgroup\aftergroup\rbrace\else
               \expandafter\next\fi}

\makeatother


\begin{document}

$\p(1)$ 
$\p[1]$ 
$\p{1}$ 
$\p(1|2)$    
\end{document}

parentheses

With automatic \left and \right. Should I also do the middle thing?

Update: added missing ̀% at end lines and thinking about the e-TeX \middle thing which is causing me some problems...

(see further down for the final method: \middle was quite a challenge)

\documentclass{article}
\usepackage{amsmath}

\makeatletter

\def\p{\afterassignment\p@aux\let\next=}

\def\p@aux{\ifx\next\bgroup
             \left\lbrace\bgroup\aftergroup\right\aftergroup\rbrace
           \else
             \ifx\next(%
                   \left(\bgroup\catcode`\)=\tw@
                   \aftergroup\right\aftergroup)%
             \else
             \ifx\next[%
                   \left[\bgroup\catcode`\]=\tw@
                   \aftergroup\right\aftergroup]%
             \else\next
             \fi\fi
           \fi}

\makeatother


\begin{document}\thispagestyle{empty}

$\p(1) \p(\dfrac{1}{2})$

$\p[1] \p[\dfrac{1}{2}]$

$\p{1} \p{\dfrac{1}{2}}$

$\p(1|2) \p(\dfrac{1}{2}|3)$
\end{document}

second


Giving justice to the eTeX \middle required a complete change of method. Note that the following works with an arbitrary delimiter after \middle

\documentclass{article}
\usepackage{amsmath} % for \dfrac 

\makeatletter

\def\p{\afterassignment\p@aux\let\next=}


\newtoks\p@toks

\def\@ybrace{\expandafter\left\expandafter\lbrace\the\p@toks\right\rbrace}
%% \def\@yparen{\expandafter\left\expandafter(\the\p@toks\right)\endgroup}
\def\@yparen{\expandafter\endgroup\expandafter\left\expandafter(\the\p@toks\right)}
%% \def\@ybrack{\expandafter\left\expandafter[\the\p@toks\right]\endgroup}
\def\@ybrack{\expandafter\endgroup\expandafter\left\expandafter[\the\p@toks\right]}

\def\p@aux{\ifx\next\bgroup
                      \def\p@tmp{\p@toks=\bgroup}%
                      \afterassignment\@ybrace
             \else
             \ifx\next(%
                   \begingroup\catcode`\)=\tw@ 
                   \def\p@tmp{\p@toks=\bgroup}%
                      \afterassignment\@yparen
             \else
             \ifx\next[%
                   \begingroup\catcode`\]=\tw@
                   \def\p@tmp{\p@toks=\bgroup}%
                      \afterassignment\@ybrack
             \else
                 \let\p@tmp\next
           \fi\fi\fi
           \p@tmp}

\makeatother


\begin{document}\thispagestyle{empty}

$\p(1) \p(\dfrac{1}{2}) \p(\dfrac{1}{2}\middle|3)$

$\p[1] \p[\dfrac{1}{2}] \p[\dfrac{1}{2}\middle|3]$

$\p{1} \p{1\middle|2} \p{\dfrac{1}{2}\middle|3}$

\end{document}

third method

$\p{1} \p{1\middle>2} \p{\dfrac{1}{2}\middle<3}$

with < in the middle


And now the method based on mathcodes. Perhaps I will have to think again on the case of the braces, which are treated here as in the previous method. For them only do I use a token list. The token list is because of \middle which makes things difficult when attempting an \aftergroup technique.

It is also because of \middle that I have to explicitely restore the mathcodes of ) and ] rather than trust it to the group which originates in the use of \left and \right. The problem is that \middle closes this group and then opens a second one.

Edit: there was a problem with $ \p( ( A ) )$ and I have edited the macros so that the mathcodes are correctly reset. I could not use the groups created by \left and \right 'cause the \middle.

\documentclass{article}

\makeatletter

\def\p{\afterassignment\p@aux\let\next=}

\newtoks\p@toks

\def\@ybrace{\expandafter\left\expandafter\lbrace\the\p@toks\right\rbrace}


% To get correct nesting I added the \restore@paren and \restore@brack macros

\def\p@aux{\ifx\next\bgroup
                      \def\p@tmp{\p@toks=\bgroup}%
                      \afterassignment\@ybrace
             \else
             \ifx\next(%
                      \ifnum\mathcode`)="8000 
                           \let\restore@paren\relax
                           \def\p@tmp{\left(}%
                     \else
                       \edef\restore@paren{\mathcode`)=\the\mathcode`)\relax}%
                       \begingroup
                         \lccode`\~=`)
                         \lowercase{%
                       \endgroup
                       \def~{\right)\restore@paren}}%
                       \def\p@tmp{\mathcode`)="8000 \left(}%
                     \fi
              \else
             \ifx\next[%
                     \ifnum\mathcode`]="8000 
                           \let\restore@brack\relax
                           \def\p@tmp{\left[}%
                     \else
                       \edef\restore@brack{\mathcode`]=\the\mathcode`]\relax}%
                       \begingroup
                         \lccode`\~=`]
                         \lowercase{%
                       \endgroup
                       \def~{\right]\restore@brack}}%
                       \def\p@tmp{\mathcode`]="8000 \left[}%
                     \fi
             \else
                 \let\p@tmp\next
           \fi\fi\fi
           \p@tmp}


\makeatother
\begin{document}\thispagestyle{empty}

\delimitershortfall=-1pt

\[\p(\frac{1}{2}\p{\p{3^T:4}}\p[\p(A_B^C)]\p(\big]\middle>\big[)\middle\Vert\p[\frac{1}{2}])\]

\[\p{\p(\p[A_B^C\middle< \p{X^Y}])\middle\vert\p[\p(A_B^C\middle> \p(X^Y))]} \]
\end{document}

nesting

\[\the\mathcode`) \ \the\mathcode`] \p( \p{ \p[ \p( \p{ \p[ A ]})]})
  \the\mathcode`)\ \the\mathcode`] \]

nesting2

share|improve this answer
1  
limitation: the "arbitrary" delimiter after \middle should not be the closing partner... –  jfbu Jan 30 '13 at 16:19
1  
I will edit the code to move the \endgroup to be the first things inside \@ybrack and \@yparen, this is better. –  jfbu Jan 30 '13 at 16:33
1  
amazingly, $\p(\p{\dfrac{1}{2}\middle<3})$ works... but exchanging braces and parentheses gives a non working input. The reason being that the catcode of the closing parenthesis will be frozen when put into the token list used for the contents of the external braces. –  jfbu Jan 30 '13 at 16:45
1  
Of course \p in the argument of a command is not guaranteed to work (or else, it's almost guaranteed not to). –  egreg Jan 30 '13 at 17:09
1  
@NicolasEssis-Breton I am truly glad it helped. I have a very strange relation to TeX "programming". It is very fascinating to have a language which is allowed to redefine (to the programmer's risk) even its most fundamental primitives. On the other hand, it has so flagrant peculiarities that I think it is really a trap to view it as a true programming framework. Also, e-TeX brought some fundamental new tools. I don't know them well so far, so I usually stick with what I read in TeX by Topic, and more recently, the TeXBook. –  jfbu Jan 30 '13 at 21:17
show 3 more comments

This does what you'd like:

\documentclass{article}
\usepackage{amsmath} % just for \dfrac in the example

\makeatletter
\def\p{\@ifnextchar(\neb@p@parens{\@ifnextchar[\neb@p@bracket\neb@p@brace}}
\def\neb@p@brace#1{\left\{#1\right\}}
\def\neb@p@bracket[#1]{\left[#1\right]}
\def\neb@p@parens(#1){\neb@p@checkbar#1||\@nil}

\def\neb@p@checkbar#1|#2|#3\@nil{%
  \if\relax\detokenize{#2}\relax
    \left(#1\right)
  \else
    \left(#1\;\middle|\;#2\right)
  \fi}
\makeatother

\begin{document}
$\p(1) \p(\dfrac{1}{2})$

$\p[1] \p[\dfrac{1}{2}]$

$\p{1} \p{\dfrac{1}{2}}$

$\p(1|2) \p(\dfrac{1}{2}|3)$
\end{document}

enter image description here

This said, I recommend against using these "flexible" commands, which are error prone: different constructs should be realized with different commands.

share|improve this answer
    
Any advantage of the explicit checkbar command compared to thr math active bar that braket package uses? –  Aditya Jan 30 '13 at 14:45
1  
@Aditya I see no advantage in using this kind of commands, so one implementation or the other is just the same. –  egreg Jan 30 '13 at 14:50
    
I just discover this \middle thing which closes and opens a group (annoying in my approach). But your code checks only for \middle| ? the e-TeX doc allows \middle<delim> –  jfbu Jan 30 '13 at 14:59
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.