매크로: 패턴에 따라 다르게 확장되나요?

매크로: 패턴에 따라 다르게 확장되나요?

그에 따른 패턴에 따라 다르게 확장되는 매크로를 작성하고 싶습니다. 특히 나는 양자 역학적 상태에 대해 더 읽기 쉬운 표기법을 허용하기 위해 그것을 사용하고 싶습니다.

% 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>; 패턴 일치는 라텍스 외부의 전처리 없이도 작동할 수 있다고 생각하는 가장 가까운 솔루션이 될 것입니다.

게다가 토큰 스트림을 분석하는 복잡한 매크로를 작성하는 것은 문서별 수준에서 수행하고 싶은 작업이 아닙니다. 예상치 못한 동작을 피하기 위해 패턴의 정의조차 쉽게 읽을 수 있도록 그러한 것들을 추상화하는 패키지가 있다면 더 좋습니다. 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

<a|b>(OP가 큰 꺾쇠 괄호와 긴 중앙 수직 막대와 같은 항목에 대해 "설정" 표기법(중괄호 사용)을 원하지 않는다는 점을 알아낸 후 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}

관련 정보