다음 패키지가 있습니다
\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}.