Ich versuche, einen Codeabschnitt zu verstehen, den ich gefunden habe

Ich versuche, einen Codeabschnitt zu verstehen, den ich gefunden habe

In diesem Thread habe ich einen Codeabschnitt gefunden, den ich wirklich interessant und nützlich fand, von dem ich aber keine Ahnung habe, wie er funktioniert:https://tex.stackexchange.com/a/584979/261033

Hier ist der betreffende Code als Referenz:

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

Es kann als aufgerufen werden und generiert eine Pmatrix. Meiner Meinung nach sehr nützlich, wenn Sie häufig mit einfachen Matrizen arbeiten und es leid sind, den ganzen langen Befehl immer wieder einzugeben. Jemand hat auch darauf hingewiesen, dass Sie das durch \matr{a,b;c,d}ersetzen müssen, damit es mit dem amsmath-Paket funktioniert .\pmatrix{\matrL}\begin{pmatrix}\matrL\end{pmatrix}

Ich möchte diesen Befehl jedenfalls noch weiter modifizieren, zum Beispiel andere Symbole als Zeilen-/Spaltentrennzeichen verwenden, die Eingabe spaltenweise analysieren oder ihn für alle Matrixklammertypen verallgemeinern (Sie könnten also etwas wie eingeben \matr{[)}{...}und es wird eine Matrix mit diesem bestimmten Satz an umschließenden Klammern generiert, ähnlich wie \left[\begin{matrix}...\end{matrix}\right)), aber ich weiß noch nicht, wie das geht.

Ich habe versucht, etwas über diese Befehle zu lernen, bin aber schnell auf Probleme gestoßen. Es scheint, dass einige von ihnen, wie beispielsweise \addto, so obskur sind, dass es nirgendwo eine Dokumentation dazu gibt! Google konnte nur Dinge wie \addtocontentsoder finden \g@addto@macro, die mich nicht interessieren, und ich konnte auch keine umfassende TeX-Ressource finden, die sie auflistet, nicht einmalhttps://www.latex-project.orgoderhttps://texdoc.org/index.html.

Wenn mir also jemand dabei helfen könnte, und mich vielleicht auf tatsächlich vorhandene Dokumentationen für diese Befehle verweisen könnte, wäre ich sehr dankbar. Vielen Dank im Voraus.

Antwort1

Das \addtoMakro hängt Code an ein anderes Makro an.

Wenn Sie haben \def\foo{X}und tun \addto\foo{Y}, wird TeX tun

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

was dazu führt

\def\foo{XY}

nachdem die \expandafterKette ihre Arbeit getan hat. SiekippenVerwenden Sie es \addto, wenn Sie den Code in LaTeX verwenden möchten, da \addtoes sich um einen wichtigen Befehl handelt babelund Sie eine Katastrophe riskieren, wenn Sie ihn neu definieren. Verwenden Sie einfach einen anderen Namen.

Was macht \matres? Es macht \def\matrL{}, wodurch ein Container für den Hauptteil der Matrix initialisiert wird. Als nächstes übergibt es das Argument an \matrA, wodurch eine Rekursion gestartet wird.

Das Makro \matrAliest einfach die folgenden Token nacheinander:

  • wenn das nächste Token ist ,(bezeichnet das Ende einer Zelle), dann &wird angehängt \matrL;
  • Wenn das nächste Token ist ;(bezeichnet das Ende einer Zeile), \crwird angehängt \matrL;
  • wenn das nächste Token ist \end, wird das Endspiel ausgeführt, d. h. \pmatrix{\matrL}die Rekursion wird beendet;
  • in allen anderen Fällen wird das Token einfach angehängt \matrL.

Kann man das an LaTeX und speziell an eine pmatrixUmgebung anpassen? Ja, problemlos.

Wählen Sie zunächst unterschiedliche Namen für die internen Makros, vorzugsweise mit @darin.

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

Derselbe Code mit minimalen Unterschieden: Anstelle von \crwird \\und \begin{pmatrix}...\end{pmatrix}verwendet.

Eine andere Implementierung mit expl3, wobei ein optionales Argument die Trennzeichen angibt (Standard p, kann bvVBmit amsmathKonventionen sein).

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

Bildbeschreibung hier eingeben

Wenn Sie auch die Zeilen- und Spaltentrennzeichen ändern möchten, können Sie ein Schlüssel-Wert-System verwenden.

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

Bildbeschreibung hier eingeben

Antwort2

Das \addtoim Code erwähnte Makro stammt aus OPmac-Makros, die ursprünglich für csplain, später OPmac für Plain TeX und heute für OpTeX entwickelt wurden. Der Autor dieser Makropakete unterstützt LaTeX nicht. Seine Makros sind in erster Linie für Plain TeX gedacht und da sie größtenteils auf TeX-Grundelementen basieren, sind sie auch in LaTeX anwendbar. Manchmal gibt es jedoch kleine Hindernisse, wie z. B. den Namen, der \addtomit dem gleichen Namen in einem LaTeX-Paket geteilt wird. Da der Autor weder LaTeX noch dessen Pakete (wie Babel) verwendet, ist dies für ihn und andere Plain-TeX-Benutzer kein Problem.

Wenn Sie das Makro ändern möchten, um den Klammertyp der Matrix im Parameter festlegen zu können, können Sie den angegebenen Typ in die Definition von \matrAdefinierteninnendas \matrMakro. Sie haben also \defeinen \defTrick:

\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

BearbeitenZum Vergleich mit einer anderen Antwort hier zeige ich, wie man Schlüssel-Wert-Makros von OpTeX verwendet:

\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

Und wenn Sie Ihr Paket mit diesem Makro erstellen möchten, sollten Sie einen separaten Namensraum verwenden ( tsskyxhier). Die Steuersequenzen in diesem Namensraum haben das Präfix .und andere verwendete Steuersequenzen (Primitive und OpTeX-Makros) haben das Präfix _. Dann ist Ihr Makro vom Benutzernamensraum (Namen ohne Präfix) und von anderen Makropaketen mit anderem Namensraum isoliert.

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

verwandte Informationen