宏:根据模式进行不同扩展?

宏:根据模式进行不同扩展?

我想编写一个宏,根据其后的模式以不同的方式展开。具体来说,我想使用它来为量子力学状态提供更易读的符号,例如

% 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 .. < ..表格)。

在 Latex 中是否存在某种功能(也许通过包),可以将单个宏与后续标记的多个模式进行匹配?

澄清因为它出现了:我不想定义命令\braket等等,或者更确切地说这是我到目前为止所做的。我正在尝试转向一种解决方案,以产生更易读的代码,虽然写作\bra <\psi_i| \Operator \ket |\psi_j>是朝着这个目标迈出的一步,但我更喜欢一种尽可能接近的形式<\psi_i|\Operator|\psi_j>;模式匹配是我能想到的最接近的解决方案,它可以在不进行乳胶之外的预处理的情况下工作。

此外,编写分析标记流的复杂宏并不是我想要在每个文档级别上做的事情。我更希望有一个包可以抽象出这些东西,这样即使模式的定义仍然易于阅读,以避免出现意外行为。如果 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

使用后缀包在某种程度上是可能的:

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

在此处输入图片描述

附言:通常\:使用的方法是使用\;,但是它们对我来说看起来太大了,你可以使用\nonscript\muskip5mu或任何你想要的来代替。

答案4

(在注意到 OP 不想要“设置”符号(带有花括号)来表示诸如<a|b>但之类的项目,而是使用大尖括号和较高的中间垂直线后,修改了 Lua 代码。)

先说一句:我强烈建议您使用不太可能出现在括号式表达式中的分隔符。这样,这些表达式的开始和结束时间就不会产生歧义。在下面的代码中,我使用&此符号;您可以随意切换到其他符号。

我希望尽可能接近<\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}

相关内容