# Macro: Expand different depending on pattern?

I want to write a macro that expands differently depending on the pattern following it. Specifically I want to use it to allow a more readable notation for quantum mechanical states, e.g.

% Non-working example
\def \m<#1|    { \left\langle #1 \right|}
\def \m|#1>    { \left|       #1 \right\rangle }
\def \m<#1>    { \left\langle #1 \right\rangle }
\def \m<#1|#2> { \left\langle #1 \middle| #2 \right\rangle }


The way LaTeX works, it can expand only one of the definitions. If I skipped the last one, a possible fix would be to change the catcode of <,|,> to 11, but that brings issues of its own (e.g. by breaking \ifnum .. < .. forms).

Is there some facility in latex, maybe through a package, that allows matching a single macro to multiple patterns of subsequent tokens?

Clarification Because it came up: I don not want to define commands \bra, ket, etc, or rather this is what I did so far. I am trying to move to a solution that results in more readable code and while writing \bra <\psi_i| \Operator \ket |\psi_j> would be a step towards that target, I'd prefer a form as close as possible to <\psi_i|\Operator|\psi_j>; Pattern matching would be the closest solution I could think of that could work without preprocessing outside of latex.

Furthermore writing complex macros, that analyze the token stream, isn't something I want to do on a per-document level. I'd prefer if there was a package that abstracts such things away, such that even the definition of the pattern remains well-readable for the sake of avoiding unexpected behaviour. If TeX's \def natively supported pattern-matching, the example code above would suit that requirement.

-
This can be done using a look-ahead but we need to know the 'conditions'. In particular, how is \m<#1| different from \m<#1|#2>? (We can look after a | for 'something' but will need a clue, for example is the first case always followed by a space?) – Joseph Wright Feb 19 at 10:14
@kdb That still doesn't answer the question I posed: how do we differentiate between the first pattern and the last one? What is it that tells us in the first case to stop and not look ahead for a closing >? – Joseph Wright Feb 19 at 12:03
@kdb But the pattern will then absorb all of the rest of the document if there is no closing >. You have to have some restriction on what can be present in #2 to allow us to know when to stop! – Joseph Wright Feb 19 at 12:24
Pattern-matching on a grabbed argument is easier (either in TeX or as @Mico suggests in Lua). However, you want to do pattern matching to define the grabbed argument, which is harder. For example, if we know that < is always ultimately followed by > we can grab everything up to > then use a variety of approaches to process the text. – Joseph Wright Feb 19 at 12:27
If you accept something like \m*...* where ... can have the various forms <#1>, <#1|, |#1>, <#1|#2> or <#1|#2|#3>, then it's doable. But without a fixed terminator it would be very hard and fragile. – egreg Feb 19 at 12:38

UPDATE Embrace the power of expl3 and xparse. I choose the delimiter ; to make the macro possible. To be honest v.2: it was quite simple and I totally lied earlier! This is the new macro

\ExplSyntaxOn
\tl_new:N \kdb_temp
\DeclareDocumentCommand{\BrKt}{u;}%
{
\left.
\tl_set:Nn \kdb_temp {#1}
\tl_replace_all:Nnn \kdb_temp{<}{\middle\langle}
\tl_replace_all:Nnn \kdb_temp{|}{\middle|}
\tl_replace_all:Nnn \kdb_temp{>}{\middle\rangle}
\tl_use:N \kdb_temp
\right.
}
\ExplSyntaxOff


Look how beautiful it is!

&< \phi | \frac{\partial^2}{\partial t^2} | \psi > &, \quad
&   <x\in\mathbf{R}^2 | 0<\abs*{\frac{x}{2}}<5 > & , \quad
& <\frac{a}{b},\frac{c}{d}> &$\medskip$ \displaystyle
&  < \phi | \frac{\partial^2}{\partial t^2} | \psi > &, \quad
&<x\in\mathbf{R}^2 | 0<\abs*{\frac{x}{2}}<5 >&,
& <\frac{a}{b},\frac{c}{d}> &$\medskip$ &<A|&, &<B|&, &|C>&,  &<D|& $\bigskip$ & <x^{2^{2^{2^{2^{2^2}}}}}|y> &\$ % with a nod to @Manuel's code :-)

Probably having \m at the start can help in avoiding problems if multiple calls are present in the same line: just stop scanning when \m is seen. – egreg Feb 19 at 15:06
I'm unsure what happens if you try <\phi| < 2 or something like that. – egreg Feb 19 at 15:11
@egreg - I decided to rework the answer so that it assumes that the braket-like expressions are delimited by symbols that act as delimiters. I suggest using & as such a delimiter; obviously, there are many other possibilities. As you and Joseph noted in earlier comments, the presence of such explicit delimiters guarantees that the pattern matching can be carried out unambiguously. – Mico Feb 19 at 16:48