我的具體例子:

我的具體例子:

我試圖以可預測的方式基於單一命令(本質上是自訂標頭)創建許多不同的命令。有沒有辦法在 TeX/LaTeX 中做到這一點?

我的具體例子:

我正在編寫一個模組規範,其中每個子標題都用\modulespec{description}{the description}或等\modulespec{learning outcomes}{the learning outcomes}表示。\mdescription{the description}\mlearningoutcomes{the learning outcomes}

我知道在類似於 bash 的擴展中結合 TeX 我會寫

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

(如果您原諒語言的組合)哪裡\getRidOfSpaces更改learning outcomeslearningoutcomes.這對 TeX/LaTeX 來說可能/可行嗎?

我(不是)我們:

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

答案1

這是 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}

在此輸入影像描述

對程式碼的一些評論。

我們定義了一個使用者級宏,用於一次定義所有模組;這\definemodules只是將控制權交給程式設計師的等級函數\farley_definemodules:n(根據 LaTeX3 程式設計指南,這是最佳實踐)。

現在,函數\farley_definemodules:n以逗號分隔其參數並對項目進行循環。目前專案可用作#1,但我們需要,##1因為我們位於定義內。

每個週期都會將項目儲存在暫存標記清單變數中,\l_farley_temp_tl以便我們可以應用\tl_replace_all:Nnn它。替換是「任何空間都被什麼都替換」;在程式環境中,空間被忽略,因此「真實空間」以 表示~

現在我們使用\cs_new_protected:cpn與舊風格類似的函數\@namedef:第一個參數被製成控制序列名稱\csname...\endcsname(令牌列表在此處透過 TeX 規則擴展)。

答案2

看起來您想要執行“for every”迴圈。 LaTeX 核心有一個宏\@for,它對逗號分隔清單中的每個元素執行此操作。您還需要\zap@space或類似的方法來刪除空格。例如:

\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

將根據需要定義\mdescription和。\mlearningoutcomes我使用了 an\edef來強制在正確的位置擴展變數。 (此處應用沒有用,\protected@edef因為「文字」內部必須「安全」\csname。)

答案3

使用\xintForLaTeX2e 核心實用程式(@名稱中帶有 ):

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

定義循環

相關內容