
我想定義一個 TeX“巨集建置”命令(讓我們稱之為\buildmacro
),它將“普通”字元字串(例如Title
)作為參數,並且滿足以下條件:
- 此命令
\buildmacro{Title}
用名稱定義計數器TitleXcounter
並將其初始化為 0。 當在檔案中的某個點發出 TeX 命令時
\Title{<arg>}
,這將具有增加計數器的效果TitleXcounter
,然後將值<arg>
放入名為 的新 TeX 巨集中\Title-<x>
,其中<x>
是當前值TitleXcounter
;這裡
<arg>
是一段 TeX 程式碼(可以包含文字、數學、任何其他 TeX 指令的段落)。
考慮以下最小範例:
\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}
我「玩」過\csname
和\endcsname
、\expandafter
、以及這些版本\def
,但沒有「運氣」。\gdef
\long
已編輯(為了回答一些評論):
這樣做的目的是有一個簡單的機制來創建一組具有相同根名稱的索引命令(類似於命令列表)。人們總是可以使用該\csname <...> \endcsname
構造來發出命令。
答案1
從所需流程的描述來看,這似乎很簡單
\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}%
}%
}
由於也要求提供普通版本
\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}%
}%
}
答案2
正如我在評論中提到的,在建立巨集名稱時,連字元和數字都不能使用,除非您始終編寫等效的內容\csname ... \endcsname
或確保在使用它們時更改目錄程式碼。
因此,有必要根據建議修改使用者介面。
基本思想似乎是創建一系列參數的索引列表,可以透過給出列表的名稱和該列表中項目的索引來檢索這些參數。
這可以使用逗號分隔的清單來實現。這是一個建議的接口,僅使用expl3
開發人員認為穩定的語法:
\buildmacro{<list identifier>}
\addmacro{<list identifier>}{<item to be added>}
\fetchmacro{<list identifier>}{<index of item to be fetched>}
\listmacro{<list identifier>}
第一個透過初始化一個新列表來進行設定。第二個將項目加入到清單中。第三個從清單中取得項目。第四個按順序列出清單中的所有項目。
概念證明(儘管不是原創的):
\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}
答案3
A\@namedef
和\@nameuse
版本,偽造「巨集」名稱,如果不更改目錄程式碼,這是不可能的。
巨集內部的分配\newcounter
可能會導致計數器暫存器出現問題。
\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}
答案4
使用列表巨集更容易獲得在偽代碼中顯示的效果,該巨集允許執行循環而無需知道其中有多少對象,也無需步進計數器。
\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}
「抽象」版本:
\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}
更容易使用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}
摘要版本
經典方法
\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}
和expl3
\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}