Definieren Sie ein Makro, das ein Makro generiert, das Argumente entgegennimmt

Definieren Sie ein Makro, das ein Makro generiert, das Argumente entgegennimmt

Ich verwende Latex schon seit einiger Zeit, aber nur auf die Grundlagen beschränkt. Ich versuche, wann immer möglich Pakete zu verwenden. Ich versuche jetzt, selbst einige Codes zu schreiben, um mein Latex-Dokument übersichtlicher zu gestalten. Das möchte ich erreichen:

Wenn ich definiere:

\symb{flow}{f_#1^#2}[a,b]

Ich möchte nutzen können

\flow        % outputs $f_a^b$
\flow[x,y]   % outputs $f_x^y$

Beachten Sie, dass die Anzahl der Indizes nicht unbedingt 2 sein muss; sie kann auch 1 oder mehr als 2 betragen.

Folgendes habe ich jetzt:

\NewDocumentCommand{\symb}{m m m}
{ \expandafter\NewDocumentCommand\csname#1\endcsname{>{\SplitList{,}}O{#3}}
    { 
        % Not sure what I need to write here
    }
}

Grundsätzlich möchte ich in der Lage sein, \symb{flow}{f_#1^#2}[a,b]ein Makro zu definieren \flow, das ein optionales Argument annimmt, nämlich einen durch Kommas getrennten Index der Variable. Falls das optionale Argument nicht angegeben wird, werden die Standardindizes (in diesem Fall a, b) verwendet.

In Python würde dies wie folgt geschrieben:

def symb(expr, default):
    def fn(*args):
        if len(args) == 0:
            return expr % args
        else:
            return expr % default

    return fn

flow = symb('$f_%s^%s$', (a, b))

flow()        % outputs $f_a^b$
flow(x, y)    % outputs $f_x^y$

Antwort1

Das ist möglich, allerdings sollten Sie Python nicht als Vorbild für die Programmierung in LaTeX nehmen.

In LaTeX werden Argumente in Klammern gesetzt und können nicht durch Kommalisten ersetzt werden.

Wie dem auch sei, hier ist eine Implementierung mit einer beliebigen Anzahl von Argumenten in der Vorlage (aber Sie müssen natürlich angeben, wie viele Sie möchten).

\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\symb}{mmmm}
 {% #1=name of command to define, #2=number of args, #3=template, #4=default

  % define the internal version
  \cs_new_protected:cn { kelvin_symb_#1:\prg_replicate:nn{#2}{n} } { #3 }

  % define the external version
  \exp_args:Nc \NewDocumentCommand { #1 } { O{#4} }
   {
    \__kelvin_symb_do:nnx { #1 } { #2 } { \clist_map_function:nN { ##1 } \__kelvin_symb_brace:n }
   }
 }

\cs_new:Nn \__kelvin_symb_do:nnn
 {
  \use:c { kelvin_symb_#1:\prg_replicate:nn{#2}{n} } #3
 }
\cs_generate_variant:Nn \__kelvin_symb_do:nnn { nnx }

\cs_new:Nn \__kelvin_symb_brace:n { {#1} }

\ExplSyntaxOff

\symb{flow}{2}{f_{#1}^{#2}}{a,b}
\symb{foo}{4}{\int_{#1}^{#2}#3\,d#4}{0,1,x,x}

\begin{document}

$\flow$

$\flow[x,y]$

$\foo$

$\foo[a,b,f(x),x]$

\end{document}

Bildbeschreibung hier eingeben

Noch ein paar Worte zum Code. Zuerst die einfachen Dinge:

\exp_args:Nc \NewDocumentCommand { #1 } { O{#4} }

ist die expl3Version von

\expandafter\NewDocumentCommand\csname#1\endcsname { O{#4 } }

und sollte bevorzugt werden.

Als nächstes eine Beschreibung der \symbFunktionsweise. Zuerst wird eine interne Funktion mit so vielen Argumenten wie deklariert definiert; ihr Ersatztext wird von der angegebenen Vorlage bereitgestellt. Damit \symb{flow}{2}{f_{#1}^{#2}}{a,b}definiert

\kelvin_symb_flow:nn { f_{#1}^{#2} }

Hinweis. Es gibt kein Problem mit der Tatsache, dass es _sich um einen Brief im Rahmen von handelt \ExplSyntaxOn, da die Erklärung \symb{flow}{2}{...}{...}gegeben wirddraußendieser Umfang.

Danach definieren wir den Befehl auf Benutzerebene \flowmit einem optionalen Argument, dessen Standard das vierte Argument von ist \symb. Dieser Befehl ruft die zuvor definierte Funktion indirekt mittels auf \__kelvin_symb_do:nnx.

Das erste Argument ist in diesem Fall , flowdas zweite ist die Anzahl der Argumente; ihr Zweck ist es, die innere Funktion aufrufen zu können. Das letzte Argument ist die Kommaliste (die Standardeinstellung oder die als optionales Argument angegebene \flow), jedoch vorverarbeitet, sodass eine Liste mit geschweiften Elementen entsteht.

Die normale Version \__kelvin_symb_do:nnnbildet einfach die interne Funktion \kelvin_symb_flow:nnund löst das dritte Argument. Aber wir verwenden eine Variante davon; wenn

\clist_map_function:nN { #1 } \__kelvin_symb_brace:n

ist vollständig erweitert (aufgrund der xVariante), wenn man a,bes darauf anwendet, erhält man {a}{b}. Somit erhalten wir

\kelvin_symb_flow:nn { a } { b }

und LaTeX erweitert sich gerne wie gewohnt auf f_{a}^{b}.

Antwort2

Sie können beispielsweise Folgendes verwenden:

\def\sdef#1{\expandafter\def\csname#1\endcsname}

\def\symb#1#2[#3,#4]{%
  \sdef{#1}{\expandafter\futurelet\expandafter\next\csname#1:a\endcsname}%
  \sdef{#1:a}{\ifx\next[\csname#1:b\expandafter\endcsname 
              \else     \csname#1:b\endcsname[#3,#4]\fi}%
  \sdef{#1:b}[##1,##2]{#2}%
}  

\symb{flow}{f_#1^#2}[a,b]

$\flow$ and $\flow[x,y]$.

Die zweite Version dieses Makros implementiert Ihre Anforderung aus den Kommentaren:

\def\sdef#1{\expandafter\def\csname#1\endcsname}
\def\addto#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}

\def\symb#1#2[#3]{%
  \sdef{#1}{\expandafter\futurelet\expandafter\next\csname#1:a\endcsname}%
  \sdef{#1:a}{\ifx\next[\csname#1:b\expandafter\endcsname 
              \else     \csname#1:c\endcsname #3,,,,,,,,\end \fi}%
  \sdef{#1:b}[##1]{\def\paramslistA{#3,}\def\paramslistB{}\setparams ##1,\end,
     \csname#1:c\expandafter\endcsname \paramslistB,,,,,,,,\end}%
  \sdef{#1:c}##1,##2,##3,##4,##5,##6,##7,##8,##9\end{#2}%
}
\def\setparams #1,{\ifx\end#1%
      \expandafter\addto\expandafter\paramslistB\expandafter{\paramslistA}%
   \else \expandafter \setparamslist \paramslistA \end #1,%
   \expandafter\setparams\fi}
\def\setparamslist#1,#2\end#3,{\def\paramslistA{#2}\addto\paramslistB{#3,}}

\symb{flow}{f_#1^#2}[a,b]

\symb{test}{test: 1=#1, 2=#2, 3=#3, 4=#4}[a,b,c,d]

$\flow$ and $\flow[x,y]$.

\test

\test[mmm]

\test[x,y,z]

Diese Lösung unterscheidet sich von der Lösung von egreg: Sie müssen keine komplizierten Makros erklären, es werden nur TeX-Grundelemente verwendet.

Antwort3

Dies ist ähnlich wie bei Wipet, macht aber das Argument für Symb obligatorisch, wie in den Kommentaren erläutert.

Bildbeschreibung hier eingeben

\documentclass{article}

\def\symb#1#2#3{%
\expandafter\def\csname x#1\endcsname##1##2{#2}%
\expandafter\newcommand\csname #1\endcsname[1][#3]{%
  \expandafter\splitcomma\csname x#1\endcsname ##1\relax}}

\def\splitcomma#1#2,#3\relax{#1{#2}{#3}}

\begin{document}

\symb{flow}{f_#1^#2}{a,b}


$\flow$

$\flow[x,y]$

\end{document}

Und eine Version, die mehrere (bis zu 8) Einträge in der Argumentliste zulässt.

Bildbeschreibung hier eingeben

\documentclass{article}

\def\symb#1#2#3{%
\expandafter\def\csname x#1\endcsname##1##2##3##4##5##6##7##8##9{#2}%
\expandafter\newcommand\csname #1\endcsname[1][#3]{%
  \expandafter\splitcomma\csname x#1\endcsname ##1,,,,,,,,,,\relax}}


\def\splitcomma#1#2,#3,#4,#5,#6,#7,#8,#9\relax{#1{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}\relax}

\begin{document}

\symb{flow}{f_#1^#2}{a,b}

\symb{flowb}{f_#1^#2g_#3^#4}{a,b,c,d}


$\flow$

$\flow[x,y]$

$\flowb$

$\flowb[x,y,w,z]$

\end{document}

verwandte Informationen