
我想編寫一個宏,根據其後面的模式進行不同的擴展。具體來說,我想用它來為量子力學狀態提供更易讀的符號,例如
% 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}
PS:\:
通常的做法是使用,\;
但它們對我來說太大了,你可以使用\nonscript\muskip5mu
或任何你想要的東西來代替。
答案4
(注意到OP不需要「設定」符號(帶有花括號)來表示諸如<a|b>
但是大尖括號和高中間垂直線之類的項目,因此修改了Lua代碼。)
預先評論:我強烈建議您使用不太可能出現在類似小括號的表達式中的分隔符號。這樣,這些表達式何時開始和何時結束就不會出現歧義。在下面的程式碼中,我使用&
as 這個符號;請隨意切換到另一款。
我更喜歡盡可能接近的形式
<\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}