Макро: Расширяется по-разному в зависимости от узора?

Макро: Расширяется по-разному в зависимости от узора?

Я хочу написать макрос, который расширяется по-разному в зависимости от следующего за ним шаблона. В частности, я хочу использовать его для более читаемой записи квантово-механических состояний, например

% 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 }

LaTeX работает так, что может расширить только одно из определений. Если бы я пропустил последнее, возможным исправлением было бы изменение catcode , <, |на >11, но это влечет за собой собственные проблемы (например, из-за поломки \ifnum .. < ..форм).

Есть ли в латексе какая-то возможность, может быть, через пакет, которая позволяет сопоставлять один макрос с несколькими шаблонами последующих токенов?

РазъяснениеПотому что возникло следующее: я не хочу определять команды \bra, ket, и т. д., или, скорее, это то, что я делал до сих пор. Я пытаюсь перейти к решению, которое приводит к более читаемому коду, и хотя написание \bra <\psi_i| \Operator \ket |\psi_j>было бы шагом к этой цели, я бы предпочел форму, максимально приближенную к <\psi_i|\Operator|\psi_j>; Сопоставление с образцом было бы самым близким решением, которое я смог придумать, которое могло бы работать без предварительной обработки вне latex.

Более того, написание сложных макросов, анализирующих поток токенов, — это не то, что я хочу делать на уровне документа. Я бы предпочел, чтобы был пакет, который абстрагирует такие вещи, чтобы даже определение шаблона оставалось легко читаемым, чтобы избежать неожиданного поведения. Если TeX \defизначально поддерживает сопоставление с шаблоном, то приведенный выше пример кода будет соответствовать этому требованию.

решение1

ОБНОВЛЯТЬПримите силу expl3и xparse. Я выбрал разделитель, ;чтобы сделать макрос возможным. Честно говоря, v.2: это было довольно просто, и я полностью лгал ранее! Это новый макрос

\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

Посмотрите, как красиво!

введите описание изображения здесь

Вы можете использовать макрос следующим образом: \BrKt<j|\otimes<k|e^{a^\dagger/\hbar}|n>\otimes|m>;, \BrKt|0>|1>|0>|1> = |3>_4;или \BrKt|m>\equiv<\Psi|A|B|\varphi>|n>;$. Это обеспечивает гораздо большее разнообразие, чем изначально предполагалось.


Старый пост Честно говоря: я не думаю, что вы не можете идеально достичь желаемого с небольшими усилиями. Хотя это возможно. Но если вы будете придерживаться основ, вы сможете использовать силу xparse. Я разработал начало

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\DeclareDocumentCommand{\m}{t< u{|} u>}%
{
    \IfBooleanTF{#1}{}{\GenericWarning{}{Watch out! A missing "<" encountered!}}
    \if\relax\detokenize{#2}\relax
        \if\relax\detokenize{#3}\relax
%           \langle\rangle
        \else
            \left| #3\right\rangle
        \fi
    \else
        \if\relax\detokenize{#3}\relax
            \left\langle #2\right|
        \else
            \left\langle #2 \middle| #3\right\rangle
        \fi
    \fi
}
\ExplSyntaxOff

Эта структура команды строго требует ввода формы \m<input1|input2>, однако она проверяет, является ли input1или input2пустым, и обрабатывает ввод соответствующим образом. Но обратите внимание, что это не может создать что-то вроде <\Psi\Phi>, без трубы посередине. Также обратите внимание, что в этой реализации открытие <не является обязательным и выдаст предупреждение только в случае его отсутствия. Надеюсь, вы сможете с этим поработать и продолжить.

решение2

Это в некоторой степени возможно с помощью пакета suffix:

\documentclass{article}
\usepackage{suffix}
\begin{document}
\WithSuffix\def\m<#1|{\left\langle #1 \right|}
\WithSuffix\def\m|#1>{\left|       #1 \right\rangle}
\[ \m<x| \quad \m|y>  \]
\end{document}

Однако в этом подходе есть существенное ограничение, поскольку один и тот же «суффикс» может быть использован только один раз, поэтому ваш предложенный \m<#1>синтаксис не может поддерживаться этим пакетом, а также \m<#1|. Это, несомненно, делает подход невозможным для запуска, но я подумал, что было бы неплохо добавить этот ответ для полноты.

решение3

С expl3предлагаемым синтаксисом \m{<x|y>}.

\documentclass{article}

\usepackage{mathtools,xparse}
\usepackage{mleftright}

\ExplSyntaxOn
\NewDocumentCommand \m { m } { \kdb_m:n {\begm#1\endm} }
\cs_new_protected:Npn \kdb_m:n #1
 {
  \group_begin:
   \tl_set:Nn \l_tmpa_tl {#1}
   \tl_replace_once:Nnn \l_tmpa_tl { \begm< } { \mleft\langle  }
   \tl_replace_once:Nnn \l_tmpa_tl { \begm| } { \mleft\lvert   }
   \tl_replace_once:Nnn \l_tmpa_tl { >\endm } { \mright\rangle }
   \tl_replace_once:Nnn \l_tmpa_tl { |\endm } { \mright\rvert  }
   \tl_replace_all:Nnn \l_tmpa_tl { | } { \:\middle\vert\: }
   \tl_use:N \l_tmpa_tl
  \group_end:
 }
\ExplSyntaxOff

\begin{document}

\[
  \m{<x>} \quad \m{<x|} \quad \m{|x>} \quad \m{<x|y|z>} \quad \m{<x^{2^{2^{2^{2^{2^2}}}}}|y>}
\]

\end{document}

И с простым LaTeX и немного другим синтаксисом \m<x|>.

\documentclass{article}

\usepackage{mathtools}
\usepackage{mleftright}

\makeatletter
\def\activevert{\@ifnextchar\mlast{\mright\rvert\@gobble}{\:\middle\vert\:}}
{\catcode`\|=\active\gdef|{\activevert}}
\gdef\m<#1>{\begingroup\mathcode`\|="8000
   \@ifnextchar|{\mleft\lvert\@gobble}{\mleft\langle}#1\mlast\endgroup}
\def\mlast{\mright\rangle}
\makeatother

\begin{document}

\[
  \m<x> \quad \m<x|> \quad \m<|x> \quad \m<x|y|z> \quad \m<x^{2^{2^{2^{2^{2^2}}}}}|y>
\]

\end{document}

введите описание изображения здесь

PS: вместо \:обычного можно использовать, \;но они кажутся мне слишком большими, вы можете использовать \nonscript\muskip5muчто угодно или что угодно.

решение4

(Пересмотрел код Lua, заметив, что автору не нужна нотация «set» (с фигурными скобками) для таких элементов, как <a|b>, а вместо этого большие угловые скобки и высокая вертикальная черта посередине.)

Комментарий заранее: я настоятельно рекомендую вам использовать символ-разделитель, который вряд ли встретится в ваших выражениях типа скобок. Таким образом, не возникнет никакой двусмысленности относительно того, когда эти выражения начинаются и когда они заканчиваются. В коде ниже я использую &этот символ; не стесняйтесь переключаться на другой.

Я бы предпочел форму, максимально приближенную к<\psi_i|\Operator|\psi_j>

Используя предлагаемую мной систему обозначений, вы бы написали & <\psi_i|\Operator|\psi_j> &.

Вот решение на основе LuaLaTeX. Функция Lua brktнастроена на сканирование каждой входной строки и выполнение последовательного сопоставления с образцом. Образцы, для которых есть совпадение, преобразуются в инструкции, которые используют макросы пакета braket-- \Braket, \Bra, и \Ket. Сканирование и замена происходят на очень ранней стадии обработки, т. е.до«Глаза» и «рот» TeX начинают свою работу.

Также предусмотрены два макроса TeX: \braketONдля запуска обработки и \braketOFFна случай, если вам потребуется остановить обработку в какой-то момент документа.

введите описание изображения здесь

% !TEX TS-program = lualatex
\documentclass{article}
\usepackage{luacode,braket,mathtools,mleftright}
\DeclarePairedDelimiter\abs\lvert\rvert % just for this example

%% Lua-side code
\begin{luacode}
function brkt ( buff )
  buff = string.gsub ( buff, "&[%s]-<([^&]-)|([^&]-)|([^&]-)>[%s]-&", "\\Braket{%1|%2|%3}" )
  buff = string.gsub ( buff, "&[%s]-<([^&]-)|([^&]-)>[%s]-&" , "\\mleft\\langle %1\\;\\middle|\\; %2\\mright\\rangle" )
  buff = string.gsub ( buff, "&[%s]-<([^&]-)>[%s]-&", "\\mleft\\langle %1\\mright\\rangle " )
  buff = string.gsub ( buff, "&[%s]-<([^&]-)%|[%s]-&", "\\Bra{%1}" )
  buff = string.gsub ( buff, "&[%s]-|([^&]-)>[%s]-&", "\\Ket{%1}" )  
  return buff
end
\end{luacode}

%% TeX-side code
\newcommand\braketON{\directlua{%
  luatexbase.add_to_callback ( "process_input_buffer", brkt, "brkt" )}}
\newcommand\braketOFF{\directlua{%
  luatexbase.remove_from_callback ( "process_input_buffer", "brkt" )}}

\begin{document}
\braketON

$
&< \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 >&,
\quad
& <\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 :-)
\end{document}

Связанный контент