Meu exemplo específico:

Meu exemplo específico:

Estou tentando criar muitos comandos diferentes com base em um único comando (essencialmente um cabeçalho personalizado) de maneira previsível. Existe uma maneira de fazer isso em TeX/LaTeX?

Meu exemplo específico:

Estou escrevendo uma especificação de módulo, onde cada um dos subtítulos é indicado por \modulespec{description}{the description}ou \modulespec{learning outcomes}{the learning outcomes}etc. Espero que o TeX possa gerar comandos como \mdescription{the description}e\mlearningoutcomes{the learning outcomes}

Eu sei que em uma expansão semelhante ao bash combinada com o TeX eu escreveria

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

(se você me desculpar a combinação de idiomas) onde \getRidOfSpacesmuda learning outcomespara learningoutcomes. Isso é possível/viável com TeX/LaTeX?

M(não)NÓS:

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

Responder1

Aqui está uma implementação do LaTeX3.

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

insira a descrição da imagem aqui

Alguns comentários sobre o código.

Definimos uma macro de nível de usuário para definir todos os módulos de uma só vez; isto é \definemodules, simplesmente entrega o controle à função de nível do programador \farley_definemodules:n(esta é a melhor prática de acordo com as diretrizes de programação do LaTeX3).

Agora a função \farley_definemodules:ndivide seu argumento entre vírgulas e faz um loop sobre os itens. O item atual está disponível como #1, mas precisamos ##1porque estamos dentro de uma definição.

Cada ciclo armazena o item na variável da lista de tokens temporários \l_farley_temp_tlpara que possamos aplicá \tl_replace_all:Nnn-lo. A substituição é “qualquer espaço é substituído por nada”; no ambiente de programação os espaços são ignorados, portanto um “espaço real” é denotado por ~.

Agora usamos a \cs_new_protected:cpnfunção que é análoga ao estilo antigo \@namedef: o primeiro argumento é transformado em um nome de sequência de controle com \csname...\endcsname(a lista de tokens é expandida aqui pela regra do TeX).

Responder2

Parece que você deseja fazer um loop 'for each'. O kernel do LaTeX possui uma macro \@forque faz isso para cada elemento de uma lista separada por vírgula. Você também precisa \zap@spaceou similar para remover espaços. Por exemplo:

\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

definirá \mdescriptione \mlearningoutcomesconforme necessário. Usei um \edefpara forçar a expansão da variável nos lugares corretos. (Não adianta aplicar \protected@edefaqui, pois o 'texto' deve ser 'seguro' por dentro \csname.)

Responder3

Usando \xintForos utilitários do kernel LaTeX2e (com um @em seus nomes):

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

loop de definição

informação relacionada