\expandafter와 비슷하게 \expandbefore를 어떻게 구현하나요?

\expandafter와 비슷하게 \expandbefore를 어떻게 구현하나요?

csname새 명령을 정의하려고 하는데 및 를 사용하여 "즉시" 새 제어 문자열을 지정합니다 endcsname.(의존성 주입 패턴을 구현하기 위한 것입니다.) **또는 로 이 작업을 수행할 수 있는 방법이 있습니까 expl3?

일반적으로 나는 ...을 사용하고 있지만 이 사용 사례에서는 다음과 같이 WITHIN 의 첫 번째 매개변수를 \expandafter\newcommand정의하고 싶습니다 .csname\newcommand

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

중괄호 안의 모든 내용을 이전에 확장하고 싶습니다 \newcommand.하지만 \expandafter이전 에 의지하지 않고\newcommand.

문제:

  • 다른 프로세스 입력 버퍼 해킹(Lua 사용)에 의존하지 않고 LaTeX에서 이 작업을 수행하는 일반적인 방법이 있는지 궁금합니다.

  • 의 매개변수 내에 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확장 컨텍스트에서는 결과를 얻으려면 4개의 -체인이 필요합니다 .

양수가 아닌 숫자를 만나면 토큰을 생성하지 않으므로 -체인 의 양을 줄이기 위해 \romannumeral약간의 -확장을 추가할 수 있습니다 . \romannumeral\expandafter

. \romannumeral\name0 foo{bar}​이렇게 하면 -token을 \expandafter타격하는 하나의 -chain 만 \romannumeral필요합니다.

또는 \romannumeral정의 내에서 -expansion을 "하드코딩"합니다. 이렇게 하면 두 개의 \expandafter-체인이 필요합니다. 의 최상위 수준 확장을 얻기 위한 첫 번째 것입니다 \name. 두 번째는 \romannumeral확장을 유도하기 위한 것입니다.

\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-expansion이 중단되고 \romannumeral토큰이 전달되지 않습니다
   \expandafter\expandafter\expandafter\f␣o␣o␣\expandafter\b␣a␣r␣\c␣r␣a␣z␣y␣  .

\name내부적으로 적용 되는 \csname동안

  • \csname확장 가능한 토큰의 확장은 일치하는 항목을 검색하는 동안 \endcsname해당 제어 시퀀스 토큰의 이름을 구성하는 문자 토큰을 수집하는 동안 발생합니다 .

  • \csname부작용으로 적용하면 문제의 제어 시퀀스가 \relax​​적용 전에 정의되지 않은 경우 문제의 제어 시퀀스에 -primitive 의 의미가 할당됩니다 \csname. \globaldefs를 적용할 때 -parameter에 양수 값이 있더라도 해당 할당은 현재 범위로 제한됩니다 \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{..}

관련 정보