Абстрактные версии

Абстрактные версии

Я хотел бы определить команду «макросоздания» TeX (назовем ее \buildmacro), которая принимает в качестве аргумента строку «обычных» символов (например, Title) и которая удовлетворяет следующим условиям:

  • команда \buildmacro{Title}определяет счетчик с именем TitleXcounterи инициализирует его значением 0.
  • при выполнении в какой-то точке файла команды TeX \Title{<arg>}это приведет к увеличению счетчика TitleXcounterи последующему помещению значения <arg>в новый макрос TeX с именем \Title-<x>, где <x>- текущее значение value 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

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

Связанный контент