Mein konkretes Beispiel:

Mein konkretes Beispiel:

Ich versuche, viele verschiedene Befehle basierend auf einem einzigen Befehl (im Wesentlichen einem benutzerdefinierten Header) auf vorhersehbare Weise zu erstellen. Gibt es eine Möglichkeit, dies in TeX/LaTeX zu tun?

Mein konkretes Beispiel:

Ich schreibe eine Modulspezifikation, in der jede der Unterüberschriften mit \modulespec{description}{the description}oder \modulespec{learning outcomes}{the learning outcomes}usw. gekennzeichnet ist. Ich hoffe, dass TeX Befehle wie \mdescription{the description}und generieren kann\mlearningoutcomes{the learning outcomes}

Ich weiß, dass ich in einer Bash-ähnlichen Erweiterung in Kombination mit TeX schreiben würde

for i in 'description' 'learning outcomes'
do
    \def\csname m\getRidOfSpaces{$i} \endcsname{\modulespec{$i}{#1}}
done

(entschuldigen Sie die Sprachenkombination), wobei \getRidOfSpacessich ändert learning outcomesin learningoutcomes. Ist dies mit TeX/LaTeX möglich/durchführbar?

M(nicht)WIR:

\documentclass{article}
\usepackage{blindtext}

% In the real thing, this definition is much more complicated
\newcommand{\modulespec}[2]{\section{#1} #2}

% The code I want in pure TeX/LaTeX
for i in 'description' 'learning outcomes'
do
    \def\csname m\getRidOfSpaces{$i} \endcsname{\modulespec{$i}{#1}}
done
% end of non TeX code


\begin{document}

% Both work
\modulespec{description}{\blindtext}
\modulespec{learning outcomes}{\blindtext}

% These two commands should produce the same output as the previous two
\mdescription{\blindtext}
\mlearningoutcomes{\blindtext}

\end{document}

Antwort1

Hier ist eine LaTeX3-Implementierung.

\documentclass{article}
\usepackage[margin=1cm]{geometry} % to fit in one page
\usepackage{blindtext}
\usepackage{xparse}

\newcommand{\modulespec}[2]{\section{#1} #2}

\ExplSyntaxOn

\NewDocumentCommand{\definemodules}{m}
 {
  \farley_definemodules:n { #1 }
 }

\tl_new:N \l_farley_temp_tl
\cs_new_protected:Npn \farley_definemodules:n #1
 {
  \clist_map_inline:nn { #1 }
   {
    \tl_set:Nn \l_farley_temp_tl { ##1 }
    \tl_replace_all:Nnn \l_farley_temp_tl { ~ } { }
    \cs_new_protected:cpn { m \l_farley_temp_tl } { \modulespec { ##1 } }
   }
 }

\ExplSyntaxOff

\definemodules{
  description,
  learning outcomes
}

\begin{document}

\modulespec{description}{\blindtext}
\modulespec{learning outcomes}{\blindtext}

% These two commands should produce the same output as the previous two
\mdescription{\blindtext}
\mlearningoutcomes{\blindtext}

\end{document}

Bildbeschreibung hier eingeben

Einige Kommentare zum Code.

Wir definieren ein Makro auf Benutzerebene, um alle Module auf einmal zu definieren. Dadurch wird \definemodulesdie Kontrolle einfach an die Funktion auf Programmiererebene übergeben \farley_definemodules:n(dies ist die bewährte Vorgehensweise gemäß den LaTeX3-Programmierrichtlinien).

Jetzt teilt die Funktion \farley_definemodules:nihr Argument an Kommas auf und führt eine Schleife über die Elemente aus. Das aktuelle Element ist als verfügbar #1, wir benötigen es jedoch ##1, da wir uns innerhalb einer Definition befinden.

Jeder Zyklus speichert das Element in der Scratch-Token-Listenvariable, \l_farley_temp_tldamit wir \tl_replace_all:Nnnes anwenden können. Der Ersatz ist „jedes Leerzeichen wird durch nichts ersetzt“; in der Programmierumgebung werden Leerzeichen ignoriert, daher wird ein „echtes Leerzeichen“ durch gekennzeichnet ~.

Nun verwenden wir die \cs_new_protected:cpnFunktion, die das Analogon zum alten Stil ist \@namedef: Das erste Argument wird in einen Steuersequenznamen umgewandelt \csname...\endcsname(die Tokenliste wird hier gemäß der TeX-Regel erweitert).

Antwort2

Es sieht so aus, als ob Sie eine „for each“-Schleife ausführen möchten. Der LaTeX-Kernel verfügt über ein Makro \@for, das dies für jedes Element einer durch Kommas getrennten Liste tut. Sie benötigen außerdem \zap@spaceoder Ähnliches, um Leerzeichen zu entfernen. Beispiel:

\newcommand{\modulespec}[2]{\section{#1} #2}
\makeatletter
\@for\@tempa:=description,learning outcomes\do{%
  \edef\@tempa
    {\expandafter\expandafter\expandafter\zap@space
      \expandafter\@tempa\space\@empty}%
  \expandafter\edef\csname m\@tempa\endcsname
    {\noexpand\modulespec{\@tempa}}%
}
\makeatother

\mdescriptionwird und nach Bedarf definieren \mlearningoutcomes. Ich habe ein verwendet, \edefum die Erweiterung der Variable an den richtigen Stellen zu erzwingen. (Es hat \protected@edefhier keinen Sinn, es anzuwenden, da der „Text“ darin „sicher“ sein muss \csname.)

Antwort3

Verwenden \xintForder LaTeX2e-Kernel-Dienstprogramme (mit einem @im Namen):

\documentclass{article}
\usepackage[english]{babel}
\usepackage{blindtext}
\usepackage{xinttools}
% In the real thing, this definition is much more complicated
\newcommand{\modulespec}[2]{\section{#1} #2}

% % The code I want in pure TeX/LaTeX
% for i in 'description' 'learning outcomes'
% do
%     \def\csname m\getRidOfSpaces{$i} \endcsname{\modulespec{$i}{#1}}
% done
% % end of non TeX code

% Nota bene: in the above you probably meant \long\def, not \def
\makeatletter
\xintFor #1 in {description, learning outcomes}\do
{\long\@namedef{m\zap@space #1 \@empty}##1{\modulespec{#1}{##1}}}
\makeatother

\begin{document}

% Both work
\modulespec{description}{\blindtext}
\modulespec{learning outcomes}{\blindtext}

% These two commands should produce the same output as the previous two
\mdescription{\blindtext}
\mlearningoutcomes{\blindtext}

\end{document}

Def-Schleife

verwandte Informationen