
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{..}