我想编写一个宏,根据其后的模式以不同的方式展开。具体来说,我想使用它来为量子力学状态提供更易读的符号,例如
% 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 中是否存在某种功能(也许通过包),可以将单个宏与后续标记的多个模式进行匹配?
澄清因为它出现了:我不想定义命令\bra
,ket
等等,或者更确切地说这是我到目前为止所做的。我正在尝试转向一种解决方案,以产生更易读的代码,虽然写作\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}