試著理解我發現的一段程式碼

試著理解我發現的一段程式碼

在這個線程上,我發現了一段非常有趣且有用的程式碼,但我不知道它是如何運作的:https://tex.stackexchange.com/a/584979/261033

這是有問題的程式碼,供參考:

\def\addto#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}
\def\matr#1{\def\matrL{}\matrA#1\end}
\def\matrA#1{\ifx\end#1\pmatrix{\matrL}\else 
   \ifx,#1\addto\matrL{&}\else
   \ifx;#1\addto\matrL{\cr}\else
   \addto\matrL{#1}\fi\fi
   \expandafter\matrA\fi
}

它可以被稱為 as\matr{a,b;c,d}並產生一個 pmatrix。在我看來,如果您經常使用簡單的矩陣並且厭倦了重複輸入完整的長命令,那麼這非常有用。有人還指出,要使其與 amsmath 包一起使用,您需要\pmatrix{\matrL}\begin{pmatrix}\matrL\end{pmatrix}.

無論如何,我希望對此命令進行進一步修改,例如使用不同的符號作為行/列分隔符,按列進行輸入解析,或者將其推廣到所有矩陣括號類型(這樣您可以輸入類似的內容,\matr{[)}{...}它將產生一個帶有一組特定的括號的矩陣,類似於\left[\begin{matrix}...\end{matrix}\right)),但我還不知道如何做到這一點。

我試圖了解一些有關這些命令的知識,但很快就遇到了問題。似乎其中一些,例如\addto,是如此晦澀難懂,以至於在任何地方都沒有關於它們的文檔! Google 只能找到類似\addtocontentsor 之類的東西\g@addto@macro,我對此不感興趣,而且我也找不到任何綜合的 TeX 資源來列出它們,甚至沒有找到https://www.latex-project.org或者https://texdoc.org/index.html

因此,如果有人可以幫助我,或向我指出這些命令的一些實際現有文檔,我將不勝感激。先感謝您。

答案1

\addto巨集將程式碼附加到另一個巨集。

如果你有\def\foo{X}並且這樣做\addto\foo{Y},TeX 就會做

\expandafter\def\expandafter\foo\expandafter{\foo Y}

這導致

\def\foo{XY}

\expandafter當鏈條完成其工作後。然而,你不能\addto如果您打算在 LaTeX 中使用程式碼,請使用它,因為\addto這是一個重要的命令,babel如果您重新定義它,您將面臨災難的風險。只需使用另一個名稱即可。

有什麼\matr作用?它確實如此\def\matrL{},它初始化了矩陣主體的容器。接下來,它將參數傳遞給\matrA,開始遞歸。

該宏\matrA只是一一讀取以下標記:

  • 如果下一個標記是,(表示單元格的末尾),則&附加到\matrL
  • 如果下一個標記是;(表示行的末尾),則\cr附加到\matrL;
  • 如果下一個標記是\end,則運行殘局,即\pmatrix{\matrL}執行完畢並停止遞歸;
  • 在所有其他情況下,令牌僅附加到\matrL.

你能將其適應 LaTeX 特別是pmatrix環境嗎?是的,很容易。

首先,為內部巨集選擇不同的名稱,最好是@in 。

\documentclass{article}
\usepackage{amsmath}

\makeatletter
\newcommand{\matr}[1]{\def\tsskyx@matrL{}\tsskyx@matrA#1\end}

\def\tsskyx@addto#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}

\def\tsskyx@matrA#1{%
  \ifx\end#1%
    \begin{pmatrix}\tsskyx@matrL\end{pmatrix}%
  \else 
    \ifx,#1%
      \tsskyx@addto\tsskyx@matrL{&}%
    \else
      \ifx;#1%
        \tsskyx@addto\tsskyx@matrL{\\}%
      \else
        \tsskyx@addto\tsskyx@matrL{#1}%
      \fi
    \fi
    \expandafter\tsskyx@matrA
  \fi
}
\makeatother

\begin{document}

\[
\matr{a,b;c,d}
\]

\end{document}

相同的程式碼,差異很小:\cr我們使用的是附加\\and\begin{pmatrix}...\end{pmatrix}來代替。

使用 的不同實現expl3,其中可選參數指定分隔符(默認p,可以bvVB使用amsmath約定)。

\documentclass{article}
\usepackage{amsmath}

\ExplSyntaxOn

\NewDocumentCommand{\matr}{O{p}m}
 {
  \tsskyx_matr:nn { #1 } { #2 }
 }

\seq_new:N \l__tsskyx_matr_body_seq

\cs_new_protected:Nn \tsskyx_matr:nn
 {
  % build the matrix
  \begin{#1matrix}
  % split the argument at ;
  \seq_set_split:Nnn \l__tsskyx_matr_body_seq { ; } { #2 }
  % map the items, that are comma separated lists
  \seq_map_function:NN \l__tsskyx_matr_body_seq \__tsskyx_matr_row:N
  \end{#1matrix}
 }

\cs_new_protected:Nn \__tsskyx_matr_row:N
 {
  \clist_use:nn { #1 } { & } \\
 }

\ExplSyntaxOff

\begin{document}

\[
\matr{a,b;c,d}
\qquad
\matr[b]{a,b;c,d}
\]

\end{document}

在此輸入影像描述

如果您還想更改行和列分隔符,可以使用鍵值系統。

\documentclass{article}
\usepackage{amsmath}

\ExplSyntaxOn

\NewDocumentCommand{\matr}{O{}m}
 {
  \group_begin:
  \keys_set:nn { tsskyx/matr } { #1 }
  \tsskyx_matr:n { #2 }
  \group_end:
 }

\seq_new:N \l__tsskyx_matr_body_seq
\seq_new:N \l__tsskyx_matr_row_seq

\keys_define:nn { tsskyx/matr }
 {
  row-sep .tl_set:N  = \l__tsskyx_matr_rowsep_tl,
  col-sep .tl_set:N  = \l__tsskyx_matr_colsep_tl,
  delim   .tl_set:N  = \l__tsskyx_matr_delim_tl,
  row-sep .initial:n = { ; },
  col-sep .initial:n = { , },
  delim   .initial:n = { p },
 }

\cs_new_protected:Nn \tsskyx_matr:n
 {
  % build the matrix
  \begin{\l__tsskyx_matr_delim_tl matrix}
  % split the argument at ;
  \seq_set_split:NVn \l__tsskyx_matr_body_seq \l__tsskyx_matr_rowsep_tl { #1 }
  % map the items, that are comma separated lists
  \seq_map_function:NN \l__tsskyx_matr_body_seq \__tsskyx_matr_row:N
  \end{\l__tsskyx_matr_delim_tl matrix}
 }

\cs_new_protected:Nn \__tsskyx_matr_row:N
 {
  \seq_set_split:NVn \l__tsskyx_matr_row_seq \l__tsskyx_matr_colsep_tl { #1 }
  \seq_use:Nn \l__tsskyx_matr_row_seq { & } \\
 }

\ExplSyntaxOff

\begin{document}

\begin{gather*}
\matr{a,b;c,d}
\\
\matr[delim=b]{a,b;c,d}
\\
\matr[row-sep=\\,col-sep=&,delim=V]{a & b \\ c & d}
\\
\matr[row-sep=;,col-sep=:]{a:b;c:d}
\end{gather*}

\end{document}

在此輸入影像描述

答案2

程式碼中提到的宏\addto來自最初為 csplain 設計的 OPmac 宏,後來是為 plain TeX 設計的 OPmac,現在在 OpTeX 中。這些巨集包的作者不支援 LaTeX。他的巨集主要用於純 TeX,並且因為它們主要基於 TeX 原語,所以它們也適用於 LaTeX。但有時會遇到一些小障礙,例如\addtoLaTeX 套件中的同名共享名稱。因為作者不使用 LaTeX 或其軟體包(如 babel),所以這對他和其他普通 TeX 使用者來說沒有問題。

如果你想修改巨集以便能夠在參數中設定矩陣的括號類型,那麼你可以將給定的類型送到\matrA定義的定義中裡面\matr。所以,你有\def訣竅\def

\def\addto#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}
\def\matr#1#2#3{\def\matrL{}%
   \def\matrA##1{\ifx\end##1\left#1\matrix{\matrL}\right#2\else 
      \ifx,##1\addto\matrL{&}\else
      \ifx;##1\addto\matrL{\cr}\else
      \addto\matrL{##1}\fi\fi
      \expandafter\matrA\fi
   }
   \matrA#3\end
}

Test and usage:
$$
  \matr[]{a,b;c,d}
$$

\bye

編輯為了與此處的另一個答案進行比較,我展示瞭如何使用 OpTeX 中的鍵值巨集:

\def\matrdefaults{%
   delims=(),   % delimiters of the matrix
   row-sep={;}, % row separator used in parameter
   col-sep={,}, % column separator used in parameter
}
\optdef\matr [] #1{{%
   \readkv\matrdefaults \readkv{\the\opt}%
   \ea\matrX \expanded{\kv{delims}\kv{row-sep}\kv{col-sep}}#1\end
}}
\def\matrX#1#2#3#4{\def\matrL{}%
   \def\matrA##1{\ifx\end##1\left#1\matrix{\matrL}\right#2\else 
      \ifx#4##1\addto\matrL{&}\else
      \ifx#3##1\addto\matrL{\cr}\else
      \addto\matrL{##1}\fi\fi
      \ea\matrA\fi
   }
   \matrA
}

$$
  \displaylines{
     \matr {a,b;c,d} \cr
     \matr [delims={[]}] {a,b;c,d} \cr
     \matr [row-sep={\cr}, col-sep={&}, delims={\|\|}] {a&b\cr c&d} \cr
     \matr [row-sep=;,col-sep=:]{a:b;c:d}
}
$$

\bye

如果您想使用此巨集建立套件,那麼您應該使用單獨的名稱空間(tsskyx此處)。此命名空間中的控制序列以 為前綴.,其他使用的控制序列(基元和 OpTeX 巨集)以 為前綴_。然後,您的巨集與使用者名稱空間(無前綴名稱)以及具有不同名稱空間的其他巨集套件隔離。

\_namespace{tsskyx}
\_def\.matrdefaults{%
   delims=(),   % delimiters of the matrix
   row-sep={;}, % row separator used in parameter
   col-sep={,}, % column separator used in parameter
}
\_optdef\.matr [] #1{{%
   \_kvdict{tsskyx}%
   \_readkv\.matrdefaults \_readkv{\_the\_opt}%
   \_ea\.matrX \_expanded{\_kv{delims}\_kv{row-sep}\_kv{col-sep}}#1\_end
}}
\_def\.matrX#1#2#3#4{\_def\.matrL{}%
   \_def\.matrA##1{\_ifx\_end##1\_left#1\_matrix{\.matrL}\_right#2\_else 
      \_ifx#4##1\_addto\.matrL{&}\_else
      \_ifx#3##1\_addto\.matrL{\_cr}\_else
      \_addto\.matrL{##1}\_fi\_fi
      \_ea\.matrA\_fi
   }
   \.matrA
}
\_nspublic \matr ;
\_endnamespace

$$
  \displaylines{
     \matr {a,b;c,d} \cr
     \matr [delims={[]}] {a,b;c,d} \cr
     \matr [row-sep={\cr}, col-sep={&}, delims={\|\|}] {a&b\cr c&d} \cr
     \matr [row-sep=;,col-sep=:]{a:b;c:d}
}
$$

\bye

相關內容