
\buildmacro
引数として「通常の」文字の文字列 (例: Title
) を受け取り、次の条件を満たすTeX の「マクロ構築」コマンド ( と呼ぶことにします) を定義したいと思います。
- コマンドは
\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
、使用時に catcodes が変更されるようにする場合は除きます。
したがって、提案されたユーザー インターフェイスを変更する必要があります。
基本的な考え方は、リストの名前とそのリスト内の項目のインデックスを指定して取得できる、一連のインデックス付き引数リストを作成することのようです。
これは、コンマ区切りのリストを使用して実装できます。expl3
開発者が安定していると判断した構文のみを使用する推奨インターフェースを次に示します。
\buildmacro{<list identifier>}
\addmacro{<list identifier>}{<item to be added>}
\fetchmacro{<list identifier>}{<index of item to be fetched>}
\listmacro{<list identifier>}
最初の関数は、新しいリストを初期化して設定を行います。2 番目の関数は、リストに項目を追加します。3 番目の関数は、リストから項目を取得します。4 番目の関数は、リスト内のすべての項目を順番にリストします。
概念実証(オリジナルとは言えませんが):
\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
バージョンでは、catcode の変更なしでは不可能な「マクロ」名を偽装しています。
マクロ内の割り当てにより、\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}