Abstrakte Versionen

Abstrakte Versionen

Ich möchte einen TeX-Befehl zum „Makro-Erstellen“ (nennen wir ihn \buildmacro) definieren, der als Argument eine Zeichenfolge „normaler“ Zeichen (z. B. Title) verwendet und Folgendes erfüllt:

  • Der Befehl \buildmacro{Title}definiert den Zähler mit dem Namen TitleXcounterund initialisiert ihn auf 0.
  • Wenn Sie an einer beliebigen Stelle in der Datei den TeX-Befehl eingeben \Title{<arg>}, hat dies zur Folge, dass der Zähler erhöht TitleXcounterund der Wert dann <arg>in ein neues TeX-Makro mit dem Namen eingefügt wird \Title-<x>, wobei <x>der aktuelle Wert von ist TitleXcounter;

    hier <arg>ist ein Stück TeX-Code (der Text, Mathematik, Absätze oder andere TeX-Befehle enthalten kann).

Betrachten Sie das folgende Minimalbeispiel:

\documentclass{article}
\usepackage{ifthen}


\def\buildmacro#1{...}% the definition of \buildmacro

\begin{document}

\buildmacro{Title}

% 'Read' several titles

\Title{The first title}
\Title{The second title}
\Title{The third title}

\newcount\tempcount
\tempcount=1\relax

% 'List' all the Titles
\whiledo{\the\tempcount<\numexpr \thetitleXcounter+1\relax}
        {%
         \textsc{\csname title-\the\tempcount\endcsname}\par
         \advance\tempcount by 1\relax
        }

\end{document}

Ich habe mit \csnameund \endcsname, \expandafter, \def, \gdefund den \longVersionen ‚gespielt‘, aber ohne ‚Glück‘.

Herausgegeben(um einige der Kommentare zu beantworten):

Der Zweck besteht darin, einen einfachen Mechanismus zum Erstellen einer Reihe indexierter Befehle mit demselben Stammnamen zu haben (ähnlich einer Befehlsliste). Man kann die \csname <...> \endcsnameKonstruktion immer verwenden, um die Befehle auszugeben.

Antwort1

Aus der Beschreibung des erforderlichen Ablaufs scheint dies recht einfach zu sein

\newcommand\buildmacro[1]{%
  % Create a new counter named after the argument
  \newcounter{#1Xcounter}%
  % Create a new command named after the argument,
  % itself taking one argument
  \expandafter\newcommand\csname #1\endcsname[1]{%
    % Step the counter
    \stepcounter(#1Xcounter)%
    % Store the argument
    \expandafter\newcommand\csname #1-\arabic{#1Xcounter}\endcsname
      {##1}%
  }%
}

Da auch eine einfache Version gewünscht wurde

\long\def\buildmacro#1{%
  \csname newcount\expandafter\endcsname\csname #1Xcounter\endcsname
  \long\expandafter\def\csname #1\endcsname##1{%
    \global\expandafter\advance\csname #1Xcounter\endcsname by 1
    \expandafter\def\csname #1-\expandafter\number\csname #1Xcounter\endcsname
      \endcsname
      {##1}%
  }%
}

Antwort2

Wie ich in einem Kommentar erwähnt habe, können beim Erstellen von Makronamen weder Bindestriche noch Ziffern verwendet werden, es sei denn, Sie schreiben immer das Äquivalent \csname ... \endcsnameoder stellen sicher, dass die Catcodes bei ihrer Verwendung geändert werden.

Daher ist es notwendig, die vorgeschlagene Benutzeroberfläche zu ändern.

Die Grundidee scheint darin zu bestehen, eine Reihe indizierter Argumentlisten zu erstellen, die abgerufen werden können, indem der Name der Liste und der Index des Elements innerhalb dieser Liste angegeben werden.

Dies könnte mit kommagetrennten Listen umgesetzt werden. Hier ist eine vorgeschlagene Schnittstelle, die nur expl3Syntax verwendet, die von den Entwicklern als stabil angesehen wird:

\buildmacro{<list identifier>}
\addmacro{<list identifier>}{<item to be added>}
\fetchmacro{<list identifier>}{<index of item to be fetched>}
\listmacro{<list identifier>}

Das erste richtet alles ein, indem es eine neue Liste initialisiert. Das zweite fügt ein Element zu einer Liste hinzu. Das dritte ruft ein Element aus einer Liste ab. Das vierte listet alle Elemente einer Liste der Reihe nach auf.

Proof of Concept (wenn auch kaum originell):

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\cs_new_protected_nopar:Nn \digitalink_buildmacro:n
{
  \clist_new:c { g_digitalink_#1_clist }
}
\NewDocumentCommand \buildmacro { m }
{
  \digitalink_buildmacro:n { #1 }
}
\NewDocumentCommand \addmacro { m +m }
{
  \clist_gput_right:cn { g_digitalink_#1_clist }
  {
    #2
  }
}
\NewDocumentCommand \fetchmacro { m m }
{
  \clist_item:cn { g_digitalink_#1_clist } { #2 }
}
\NewDocumentCommand \listmacro { m }
{
  \clist_use:cn { g_digitalink_#1_clist } { \par }
}
\ExplSyntaxOff
\begin{document}
\buildmacro{dititle}
\addmacro{dititle}{Here's some text.}
\addmacro{dititle}{Here's some more.}
\fetchmacro{dititle}{1}
\fetchmacro{dititle}{2}
\fetchmacro{dititle}{1}

List:

\listmacro{dititle}
\end{document}

konzeptioneller Beweiß

Antwort3

Eine Version, \@namedefdie \@nameuse„Makro“-Namen vortäuscht, was ohne Catcode-Änderung nicht möglich wäre.

Die Zuweisung \newcounterinnerhalb von Makros kann zu Problemen mit Zählerregistern führen.

\documentclass{article}

\makeatletter
\newcommand{\buildmacro}[1]{%
  \newcounter{#1Xcounter}%
    \expandafter\newcommand\csname #1\endcsname[1]{%
      \stepcounter{#1Xcounter}%
      \@namedef{#1-\number\value{#1Xcounter}}{##1}%
  }
}

\newcommand{\displaymacrocontent}[2]{%
  \@nameuse{#1-#2}%
}
\makeatother



\begin{document}

\buildmacro{Title}
\Title{The first title}
\Title{The second title}
\Title{The third title}

\newcount\tmpcntr

\loop\unless\ifnum\tmpcntr > 4
\advance\tmpcntr by 1
\displaymacrocontent{Title}{\number\tmpcntr}

\repeat



\end{document}

Bildbeschreibung hier eingeben

Antwort4

Der Effekt, den Sie in Ihrem Pseudocode zeigen, lässt sich viel einfacher mit einem Listenmakro erzielen, das die Ausführung einer Schleife ermöglicht, ohne dass man wissen muss, wie viele Objekte sich darin befinden, und ohne Zähler weiterzuschalten.

\documentclass{article}

\makeatletter
\newcommand{\Titlecontainer}{\@empty}% initialize
\newcommand{\Title}[1]{%
  \expandafter\def\expandafter\Titlecontainer\expandafter{%
    \Titlecontainer\LISTSEP{#1}%
  }%
}
\makeatother

\begin{document}

\Title{The first title}
\Title{The second title}
\Title{The third title}

% 'List' all the Titles
\begingroup % keep the change to \LISTSEP local
\def\LISTSEP#1{\textsc{#1}\par}
\Titlecontainer
\endgroup

\end{document}

Bildbeschreibung hier eingeben

Eine „abstrakte“ Version:

\documentclass{article}

\makeatletter
\newcommand{\Titlecontainer}{\@empty}% initialize
\newcommand{\Title}[1]{%
  \expandafter\def\expandafter\Titlecontainer\expandafter{%
    \Titlecontainer\LISTSEP{#1}%
  }%
}
\newcommand{\listmap}[2]{% #1 is the list name, #2 the code
  \begingroup\def\LISTSEP##1{#2}#1\endgroup
}
\makeatother

\begin{document}

\Title{The first title}
\Title{The second title}
\Title{The third title}

% 'List' all the Titles
\listmap{\Titlecontainer}{\textsc{#1}\par}

\end{document}

Noch einfacher mit expl3:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\Title}{m}
 {
  \seq_put_right:Nn \digitalink_titles_seq { #1 }
 }
\NewDocumentCommand{\ProcessTitles}{+m}
 {
  \seq_map_inline:Nn \digitalink_titles_seq { #1 }
 }
\seq_new:N \digitalink_titles_seq
\ExplSyntaxOff

\begin{document}

\Title{The first title}
\Title{The second title}
\Title{The third title}

\ProcessTitles{\textsc{#1}\par}

\newcounter{titlecount}
\ProcessTitles{\stepcounter{titlecount}\arabic{titlecount} -- #1\par}

\end{document}

Bildbeschreibung hier eingeben


Abstrakte Versionen

Klassische Methode

\documentclass{article}

\makeatletter
\newcommand{\definelist}[1]{%
  \@namedef{#1}##1{%
    \expandafter\def\csname #1@container\expandafter\expandafter\expandafter\endcsname
    \expandafter\expandafter\expandafter{%
      \csname #1@container\endcsname\LISTSEP{##1}%
    }%
  }%
  \@namedef{#1@container}{\@empty}% initialize
}
\newcommand{\maplist}[2]{%
  \begingroup
  \def\LISTSEP##1{#2}%
  \@nameuse{#1@container}%
  \endgroup
}
\makeatother

\definelist{Title}

\begin{document}

\Title{The first title}
\Title{The second title}
\Title{The third title}

% 'List' all the Titles
\maplist{Title}{\textsc{#1}\par}

\newcounter{tempcount}
\maplist{Title}{\stepcounter{tempcount}\arabic{tempcount} -- #1\par}

\end{document}

Mitexpl3

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\definelist}{m}
 {
  \seq_new:c { l_digitalink_list_#1_seq }
  \cs_new_protected:cpn { #1 } ##1
   {
    \seq_put_right:cn { l_digitalink_list_#1_seq } { ##1 }
   }
 }
\NewDocumentCommand{\maplist}{m +m}
 {
  \seq_map_inline:cn { l_digitalink_list_#1_seq } { #2 }
 }
\ExplSyntaxOff

\definelist{Title}

\begin{document}

\Title{The first title}
\Title{The second title}
\Title{The third title}

% 'List' all the Titles
\maplist{Title}{\textsc{#1}\par}

\newcounter{tempcount}
\maplist{Title}{\stepcounter{tempcount}\arabic{tempcount} -- #1\par}

\end{document}

verwandte Informationen