\csname, \expandafter, \csuse, \@namedef ...를 사용하는 방법은 무엇입니까?

\csname, \expandafter, \csuse, \@namedef ...를 사용하는 방법은 무엇입니까?

다음 패키지가 있습니다

\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{mypkg}

\providecommand*\@mycmd{No {\MakeUppercase Mycmd} defined}
\newcommand*\Mycmd[1]{\renewcommand*\@mycmd{#1}}

\newcommand*\showDF[1]{\csname @#1\endcsname}

\endinput

\Mycmd{}사용자에게 갱신 명령을 제공 \@mycmd하고 \showDF{mycmd}내용을 표시합니다.

\documentclass[a4paper,titlepage,11pt,twoside,openright]{report}
\usepackage{mypkg}
\begin{document}

\showDF{mycmd}\par
\Mycmd{Test}
\showDF{mycmd}

\end{document}

여러 cmd 쌍을 생성하기 위해 처음 두 명령을 매크로로 정의하고 싶습니다.

\@newDF{mycmd}{Mycmd}

나는 시도했다

\newcommand*\@newDF[2]{
 \providecommand*\csname @#1\endcsname{No {\MakeUppercase #2} defined}
 \newcommand*\csname #2\endcsname[1]{\renewcommand\csname @#1\endcsname{##1}}
}

하지만 실행되지 않습니다.

\newcommand*\newDF[2]{
 \expandafter\providecommand\expandafter*\csname @#1\endcsname{No {\MakeUppercase #2} defined}
 \expandafter\newcommand\expandafter*\csname #2\endcsname[1]{\renewcommand\csname @#1\endcsname{##1}}
}

컴파일하지만 왜 거기에 넣었는지 정말 모르겠습니다 \expandafter. 어쨌든 실행될 \MakeUppercase때 무시되고 아무런 효과가 없습니다. 둘 중 하나로 바꾸 거나 둘 다 작동하지 않습니다. 내가 무엇을 놓치고 있나요?\showDF{mycmd}\Mycmd{Hi}\csname @#1\endcsname@nameuse{@#1}\csuse{@#1}

답변1

간단히 말해서, 사용이 실패하는 이유는 \expandafter사용이 충분하지 않기 때문입니다. 자세한 내용은 이 사이트의 다른 곳에서 이에 대한 설득력 있는 설명을 참조하세요.4개의 토큰을 올바른 순서로 확장하려면 왜 11개의 확장이 필요한가요?.

당신이 겪고 있는 문제 \MakeUppercase는 확장이 불가능하기 때문에 정의 내에서 직접 사용할 수 없다는 것입니다 \csname...\endcsname. 해당 게시물의 답변에 자세히 설명되어 있습니다. csname을 사용하여 대문자화된 매크로 토큰 만들기.

Werner는 대문자로 표시된 이름과 대문자로 쓰지 않은 이름을 모두 매크로 작성자에게 전달하여 대문자 문제를 방지하는 한 가지 솔루션을 제공했습니다. 다음은 매크로 이름을 자동으로 "대문자"로 바꾸는 또 다른 솔루션입니다.

를 사용하여 이미 정의되어 있는지 \providescommand확인하는 대신 사용을 사용하면 피하고 싶은 일부 가 필요하므로 직접 확인합니다. 마지막으로, 보너스로 아래 코드는 쉼표로 구분된 목록에서 이러한 명령 계열을 생성하기 위한 "팩토리 함수"도 정의합니다.\@my<command>\ifcsdef\providescommand\expandafter\@DefineMyCommands

\documentclass{article}
\usepackage{etoolbox}

\makeatletter

\newcommand\@DefineMyCommand[1]{\@ReallyDefineMyCommand#1\relax}
\def\@ReallyDefineMyCommand#1#2\relax{%
  % Define command <#1#2> to set @my#1#2={arg of <#1#2>}
  % Here #1 is the first character of the comamnd and #2 is the rest.
  % We have isolated #1 so that we can uppercase it on the next line
  \uppercase{\expandafter\gdef\csname #1}#2\endcsname##1{\@namedef{@my#1#2}{##1}}
  % if \@my#1#2 is not already defined then define it
  \ifcsdef{@my#1#2}{\relax}{\@namedef{@my#1#2}{No \MakeUppercase{#1#2} defined!}}
}
\newcommand{\@DefineMyCommands}{\forcsvlist{\@DefineMyCommand}}% factory function

\@DefineMyCommands{mycmd, test, fred, julie}% define a bunch of macros

\makeatother

\newcommand*\showDF[1]{\csname @my#1\endcsname}

\begin{document}

\showDF{mycmd}

\Mycmd{A command!}

\showDF{mycmd}

\showDF{test}

\Test{A test!}

\showDF{test}

\end{document}

"예상되는" 출력은 다음과 같습니다.

여기에 이미지 설명을 입력하세요

편집하다실제로, 팩토리 명령을 정의하는 것은 한 번만 사용된다면 조금 어리석은 일입니다. 이러한 매크로가 많지 않다면 작성하는 것이 더 현명할 것입니다.

\forcsvlist{\@DefineMyCommand}{mycmd, test, fred, julie}

\@DefineMyCommand이는 불필요한 매크로를 생성하지 않고 목록의 요소에 명령을 적용하기 때문입니다 .

답변2

이를 수행하는 방법은 다음과 같습니다.

\documentclass{article}
\makeatletter
%\providecommand*\@mycmd{No {\MakeUppercase Mycmd} defined}
%\newcommand*\Mycmd[1]{\renewcommand*\@mycmd{#1}}

\newcommand{\@newDF}[2]{%
  \@namedef{@#1}{No \MakeUppercase{#2} defined}%
  %\expandafter\newcommand\csname @#1\endcsname{No \MakeUppercase{#2} defined}% Alternative to above
  \expandafter\newcommand\csname #2\endcsname[1]{%
    \expandafter\renewcommand\csname @#1\endcsname{##1}}
}
\@newDF{mycmd}{Mycmd}
\newcommand*\showDF[1]{\csname @#1\endcsname}
\makeatother
\begin{document}

\showDF{mycmd}\par
\Mycmd{Test}
\showDF{mycmd}

\end{document}

출력은 다음과 같습니다

MYCMD가 정의되지 않음
테스트

그만큼정의는\show:

> \@mycmd=macro:
->No \MakeUppercase {Mycmd} defined.


> \Mycmd=\long macro:
#1->\expandafter \renewcommand \csname @mycmd\endcsname {#1}.

관련 정보