
Я хочу написать макрос, который расширяется по-разному в зависимости от следующего за ним шаблона. В частности, я хочу использовать его для более читаемой записи квантово-механических состояний, например
% 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}