Как реализовать \expandbefore, аналогично \expandafter?

Как реализовать \expandbefore, аналогично \expandafter?

Я пытаюсь определить новую команду, но указываю новую управляющую строку «на лету» с помощью csnameи endcsname.(Это делается с целью реализации шаблона внедрения зависимостей.) **Или есть ли способ сделать это с помощью expl3?

Обычно я использую \expandafter\newcommand..., но в этом случае я хотел бы определить первый параметр csnameWITHIN \newcommand, например так:

\newcommand{\expandbefore\csname \GetCommandName \endcsname}[1]{\small I did it!!!}
\newcommand\expandbefore\csname \GetCommandName \endcsname{\small I did it again!!!}

Я бы хотел, чтобы все, что находится внутри фигурных скобок, было расширено ДО того, как \newcommand...но не полагаясь на \expandafterранее\newcommand.

Проблемы:

  • Мне интересно, есть ли нормальный способ сделать это в LaTeX, не прибегая к другому хаку входного буфера процесса (с Lua).

  • Добавление expandafter, nameuse, edef, let, csname, и т. д. в \newcommandпараметр ' приводит только к ошибке переопределения этих команд. (Даже если они находятся в замыканиях {}или begingroup.

  • Попытка \meaning \expandafterпонять, как это работает, не удалась (что предсказуемо и забавно).

решение1

Я (с небольшими изменениями) цитирую свойотвечатьна вопросОпределите последовательность управления, после которой пробел имеет значение.поскольку это, по-видимому, применимо и к вашему вопросу:


Применяя #{-нотацию, вы можете определить макросы, последний аргумент которых отделен открывающей фигурной скобкой. В отличие от других разделителей аргументов, которые удаляются при сборе аргументов, TeX оставит на месте разделяющую открывающую фигурную скобку.
(На самом деле механизм не ограничивается токенами символов открывающей фигурной скобки. Вы можете использовать любой токен, код категории которого равен 1 во время определения. Также может быть #\WeIrdпосле \let\WeIrd={  .)
Разделенные аргументы могут быть пустыми.

Поэтому для получения токена управляющей последовательности из набора токенов, который расширяется до набора токенов символов, который формирует имя рассматриваемого токена управляющей последовательности как для определения, так и для вызова этого токена управляющей последовательности, вы можете (применив -нотацию #{) придумать одну управляющую последовательность \name, которая обрабатывает аргумент, разделенный фигурными скобками, за которым следует неразделенный аргумент (который вложен в фигурные скобки). После того, как TeX извлечет аргументы, вы можете заставить TeX вращать их и применять \csname..\endcsnameк аргументу, указанному внутри фигурных скобок. Имя рассматриваемого токена управляющей последовательности может также содержать пробельные токены.

\makeatletter
%
\newcommand\name{}%
\long\def\name#1#{\UD@innername{#1}}%
%
\newcommand\UD@innername[2]{%
  \expandafter\UD@exchange\expandafter{\csname#2\endcsname}{#1}%
}%
%
\newcommand\UD@exchange[2]{#2#1}%
%
\makeatother

\name foo{bar}→ шаг расширения 1:
\UD@innername{foo}{bar}→ шаг расширения 2:
\expandafter\UD@exchange\expandafter{\csname bar\endcsname}{foo}→ шаг расширения 3:
\UD@exchange{\bar}{foo}→ шаг расширения 4:
foo\bar  .

\expandafterВ контексте расширения для получения результата вам понадобятся четыре -цепочки.

Так как \romannumeralпри обнаружении неположительного числа не создается никаких токенов, можно добавить немного \romannumeral-расширения, чтобы уменьшить количество \expandafter-цепочек.

Либо сделайте \romannumeral\name0 foo{bar}. Таким образом, нужна только одна \expandafter-цепочка, достигающая -токена.\romannumeral

Или иметь \romannumeral-expansion "жестко закодированным" в определении — таким образом, \expandafterнеобходимы две -цепочки. Первая для получения расширения верхнего уровня \name. Вторая для индуцирования \romannumeral-expansion.

\makeatletter
%
\newcommand\name{}%
\long\def\name#1#{\romannumeral0\UD@innername{#1}}%
%
\newcommand\UD@innername[2]{%
  \expandafter\UD@exchange\expandafter{\csname#2\endcsname}{ #1}%
}%
%
\newcommand\UD@exchange[2]{#2#1}%
%
\makeatother

С таким макросом вы не привязаны к конкретным командам определения:

\name{foo}\foo  .    (←Это способ, при котором вы не определяете, а просто вызываете/используете управляющие последовательности с помощью \name.)

\name\newcommand{foo}\newcommand\foo  .

\name\DeclareRobustCommand{foo}\DeclareRobustCommand\foo  .

\name\global\long\outer\def{foo}\global\long\outer\def\foo  .

\name\expandafter{foo}\bar\expandafter\foo\bar  .

\name\let{foo}=\bar\let\foo=\bar  .

\name\string{foo}\string\foo  .

\name\meaning{foo}\meaning\foo  .

Вы также можете использовать такой макрос для определения/вызова макросов, имена которых содержат пробелы:

\name{foo }\foo␣  .

\name\newcommand{foo }\newcommand\foo␣  .

\name\DeclareRobustCommand{foo }\DeclareRobustCommand\foo␣  .

\name\global\long\outer\def{foo }\global\long\outer\def\foo␣  .

\name\expandafter{foo }\bar\expandafter\foo␣\bar  .

\name\let{foo }=\bar\let\foo␣=\bar  .

\name\string{foo }\string\foo␣  .

\name\meaning{foo }\meaning\foo␣  .

При сборе имени рассматриваемого токена управляющей последовательности \nameбудет запущено расширение расширяемых токенов:

\def\GetCommandName{FooBar}
\name\newcommand{\GetCommandName}[1]{\small I did it!!!}

\newcommand\FooBar[1]{\small I did it!!!}

\def\GetCommandName{\CommandNamePartA\CommandNamePartB}
\def\CommandNamePartA{Ba}
\def\CommandNamePartB{r\InnerCommandNamePart o}
\def\InnerCommandNamePart{Fo}
\name\newcommand{\GetCommandName}{\small I did it again!!!}

\newcommand\BarFoo{\small I did it again!!!}

Вы также можете вкладывать вызовы в \name:

Пример 1:

   \name\name\expandafter{f o o }{b a r }

Обработка первых \nameурожаев:
   \name\expandafter\f␣o␣o␣{b a r }  .

Обработка второго \nameдает:
   \expandafter\f␣o␣o␣\b␣a␣r␣  .

(Аналогично: \name\name\let{f o o }={b a r }\let\f␣o␣o␣=\b␣a␣r␣.)

Пример 2:

   \name\name\name\expandafter\expandafter\expandafter{f o o }\expandafter{b a r }{c r a z y }

Обработка первых \nameурожаев:
   \name\name\expandafter\expandafter\expandafter\f␣o␣o␣\expandafter{b a r }{c r a z y }  .

Обработка второго \nameдает:
   \name\expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣{c r a z y }  .

Обработка третьего \nameдает:
   \expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣\c␣r␣a␣z␣y␣  .

Пример 3:

В контексте расширения вы можете использовать \romannumeral-expansion, чтобы все продолжалось.

   \romannumeral\name\name\name0 \expandafter\expandafter\expandafter{f o o }\expandafter{b a r }{c r a z y }

\romannumeralпродолжает расширяться, пока не найдет какое-то число. В конце концов он найдет число 0, а с неположительными числами \romannumeralне доставит никакого токена:
   %\romannumneral-expansion in progress
   \name\name\name0 \expandafter\expandafter\expandafter{f o o }\expandafter{b a r }{c r a z y }

Обработка первых \nameурожаев:
   %\romannumneral-expansion in progress
   \name\name0 \expandafter\expandafter\expandafter\f␣o␣o␣\expandafter{b a r }{c r a z y }  .

Обработка второго \nameдает:
   %\romannumneral-expansion in progress
   \name0 \expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣{c r a z y }  .

Обработка третьего \nameдает:
   %\romannumneral-expansion in progress
   0 \expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣\c␣r␣a␣z␣y␣  .

Теперь \romannumeralнаходит число 0. Поэтому \romannumeral-расширение прерывается и \romannumeralне доставит никакого токена:
   \expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣\c␣r␣a␣z␣y␣  .

Имейте в виду, что \nameвнутреннее применяется \csnameво время

  • Расширение расширяемых токенов происходит, пока \csnameво время поиска соответствия \endcsnameсобираются токены символов, которые образуют имя рассматриваемого токена управляющей последовательности.

  • применение \csnameв качестве побочного эффекта приводит к назначению рассматриваемой управляющей последовательности значения -примитива \relaxв случае, если рассматриваемая управляющая последовательность была не определена до применения \csname. Это назначение будет ограничено текущей областью действия, даже если \globaldefs-параметр имел положительное значение во время применения \csname.

 

%%\errorcontextlines=1000
\documentclass[a4paper]{article}
\usepackage{textcomp}%

\parindent=0cm
\parskip=\medskipamount

\makeatletter
\newcommand\name{}%
\long\def\name#1#{\romannumeral0\UD@innername{#1}}%
\newcommand\UD@innername[2]{%
  \expandafter\UD@exchange\expandafter{\csname#2\endcsname}{ #1}%
}%
\newcommand\UD@exchange[2]{#2#1}%
\makeatother


\name\newcommand{foo}[2]{%
  Control sequence whose name does not contain any space.\\
  Argument 1: \textit{\textlangle#1\textrangle}\\
  Argument 2: \textit{\textlangle#2\textrangle}
}%

\name\newcommand{foo }[2]{%
  Control sequence whose name has a trailing space.\\
  Argument 1: \textit{\textlangle#1\textrangle}\\
  Argument 2: \textit{\textlangle#2\textrangle}
}%

\name\newcommand{ f o o }[2]{%
  Control sequence whose name is interspersed with spaces.\\
  Argument 1: \textit{\textlangle#1\textrangle}\\
  Argument 2: \textit{\textlangle#2\textrangle}
}%

\newcommand*\GetCommandName{\CommandNamePartA\CommandNamePartB}
\newcommand*\CommandNamePartA{Ba}
\newcommand*\CommandNamePartB{r\InnerCommandNamePart o}
\newcommand*\InnerCommandNamePart{Fo}
\name\newcommand{\GetCommandName}{\small I did it again!!!}

\begin{document}

\name{foo}{Arg 1}{Arg 2}

\name{foo }{Arg 1}{Arg 2}

\name{ f o o }{Arg 1}{Arg 2}

Nesting \texttt{\string\name}:

\name\expandafter\newcommand\expandafter*\expandafter{C o N f u SiO n}\expandafter{%
  \romannumeral\name\name\name0 %
  \expandafter\expandafter\expandafter{F O O}\expandafter{B A R}{C R A Z Y}%
}%
\texttt{\name\string{C o N f u SiO n} is \name\meaning{C o N f u SiO n}}%
\\

Playing around with expandable tokens:  

\texttt{\name\string{\GetCommandName}:}
\texttt{\name\meaning{\GetCommandName}}

\name{\GetCommandName}%

Playing around with grouping:

%Be aware that \texttt itself opens up a new scope for typesetting its argument.

%\globaldefs=1\relax

\texttt{%
  \begingroup\name\string{w e i r d } is  \name\endgroup\meaning{w e i r d }%
}%

\texttt{%
  \name\string{w e i r d } is  \name\meaning{w e i r d }%
}%

\end{document}

введите описание изображения здесь

решение2

В LaTeX уже есть форма команды, которая принимает имя команды, а не токен csname:

\@namedef{\GetCommandName}{\small I did it!!!}

должен делать то, что хочешь, это просто\expandafter\def\csname\GetCommandName\endcsname{..}

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