별표 표시된 명령 버전을 추가하는 매크로

별표 표시된 명령 버전을 추가하는 매크로

명령에 별표 버전을 추가하는 메타 매크로를 어떻게 작성할 수 있습니까?

사용 목적은 다음과 같습니다.

\newcommand\foo[1]{foo is #1}
\addstarred\foo[2]{foo is #1, bar is #2}

답변1

suffixDavid Kastrup의 패키지에는 이미 방법이 제공되어 있습니다 . 말할 필요도 없이 기발한 트릭이 가득합니다.

당신은 말할 수 있습니다

\usepackage{suffix}

\newcommand{\foo}[1]{foo is #1}
\WithSuffix\newcommand\foo*[2]{foo is #1, bar is #2}

목표가 어떻게 달성되는지 확인하는 것이 유익할 수 있습니다.

두 번째 지시 이후에 수행하면 \show\foo다음을 찾습니다.

> \foo=\protected macro:
->\WSF@suffixcheck \foo .

suffix그래서 우리는 e-TeX(요즘에는 문제가 되지 않음)가 필요하다는 것을 배우고 \foo를 의미하도록 재정의합니다 \WSF@suffixcheck\foo. 그래서 우리는 를 추가 \makeatletter하고 시도 \show\WSF@suffixcheck합니다.

> \WSF@suffixcheck=macro:
#1->\begingroup \def \reserved@a {#1}\futurelet \reserved@b \WSF@suffixcheckii 

따라서 인수는 다음 위치에 저장됩니다 \reserved@a.

\futurelet\reserved@b\WSF@suffixcheckii

실행됩니다. 이는 을 \reserved@b따르는 토큰과 동일하게 만듭니다 \WSF@suffixcheckii. 전화가

\foo{foo}

그러면 \reserved@b될 것이다 \bgroup; 전화가 오면

\foo*{foo}{bar}

그러면 \reserved@b될 것입니다 *. 이제 우리는 무엇을 하는지 알아야 합니다 \WSF@suffixcheckii:

> \WSF@suffixcheckii=macro:
->\ifcsname \expandafter \SuffixName \reserved@a \reserved@b \endcsname
  \expandafter \WSF@suffixcheckiii \else \expandafter \WSF@suffixcheckiv \fi .

좋아, 다음 경우에 무슨 일이 일어나는지 봅시다 \foo{foo}: \reserved@a로 확장되고 \foo, 는 \reserved@b( \bgroup확장 불가능)이므로 TeX는 처음으로 다음과 같이 제시됩니다.

\ifcsname\SuffixName\foo\reserved@b\endcsname

그리고 \SuffixName다음과 같이 정의됩니다.

> \SuffixName=\long macro:
#1->WSF:\string #1 \meaning .

그래서 다음 단계는

\ifcsname WSF:\string\foo \meaning\reserved@b\endcsname

그리고 우리는 마침내 얻습니다

\ifcsname WSF:\foo begin-group character {\endcsname

여기서 모든 문자의 범주 코드는 12입니다(그러나 공백은 10입니다). \foo*{foo}{bar}우리가 얻을 경우

\ifcsname WSF:\foo the character *\endcsname

명령이 \csname WSF:\foo begin-group character {\endcsname정의되지 않았으므로 잘못된 분기를 따릅니다.

\expandafter \WSF@suffixcheckiv \fi

그것은 단순히 떠난다

\WSF@suffixcheckiv{foo}

입력 스트림에서. 이제 \show\WSF@suffixcheckiv준다

> \WSF@suffixcheckiv=macro:
->\expandafter \endgroup \csname \expandafter \NoSuffixName \reserved@a \endcsname .

이전에 열린 그룹은 닫혀 있지만 먼저

\csname \expandafter \NoSuffixName \reserved@a \endcsname

로 이루어져. \reserved@a로 확장된다는 점을 상기하면 \foo, 우리는 다음을 얻습니다.

\csname \NoSuffixName \foo \endcsname

그리고 \NoSuffixName

> \NoSuffixName=macro:
->WSF:\string .

그래서 마침내 우리는 얻습니다

\csname WSF:\string\foo\encsname

좋아, 다음을 발행해 보자 \expandafter\show\csname WSF:\string\foo\endcsname:

> \WSF:\foo=\long macro:
#1->foo is #1.

즉, 이 복잡한 매크로는 원본 \foo.

\foo*{foo}{bar}우리 의 경우에는

\ifcsname WSF:\foo the character *\endcsname

하지만 이 경우에는~이다한정된; 물론

\expandafter\show\csname WSF:\string\foo\space the character *\endcsname

생산하다

> \WSF:\foo the character *=\long macro:
#1#2->foo is #1, bar is #2.

따라서 이름이 복잡한 이 매크로는 -variant로 정의한 것입니다 *.

이 패키지에서는 거의 모든 토큰을 접미사로 사용할 수 있습니다. 그러나 본질적인 아이디어는 당신이 고안한 것과 다르지 않습니다. 가능한 기존 매크로 이름을 덮어쓰는 것에 대한 보호 기능이 더 좋습니다. 언제 패키지가 하는 일

\WithSuffix\newcommand\foo*[2]{foo is #1, bar is #2}

처리됩니다

  1. 원래 \foo명령을 아래에 저장하십시오.

    \csname WSF:\string\foo\endcsname
    

    \WithSuffix(이 단계 에 적용된 선행 작업으로 인해 이미 존재하는 경우 \foo당연히 생략됩니다.)

  2. 아래에 새 정의를 저장합니다.

    \csname WSF:\string\foo\space the character *\endcsname
    
  3. 위에서 설명한 추상 인터페이스를 사용하여 다양한 접미사 중에서 선택하세요.

답변2

해결책에 대한 내 시도는 @egreg 및 @DavidCarlisle이 친절하게 제공한 개선 사항과 함께 아래에 나와 있습니다.

\documentclass{standalone}

\makeatletter
\newcommand\addstarred[1]{%
    \expandafter\let\csname\string#1@nostar\endcsname#1%
    \edef#1{\noexpand\@ifstar\expandafter\noexpand\csname\string#1@star\endcsname\expandafter\noexpand\csname\string#1@nostar\endcsname}%
    \expandafter\newcommand\csname\string#1@star\endcsname%
}
\makeatother

\newcommand\foo[1]{foo is #1}
\addstarred\foo[2]{foo is #1, bar is #2}

\begin{document}
    \foo{red} --- \foo*{red}{green}
\end{document}

결과:

MWE 출력

설명:

  • 명령의 현재 정의 사본 \foo은 로 저장됩니다 \\foo@nostar.
  • \foo별표를 확인하고 또는 \\foo@star를 호출하도록 명령이 재정의되었습니다 \\foo@nostar. 이는 edef명령이 호출될 때마다가 아니라 구성된 토큰 이름이 제자리에서 확장될 수 있도록 수행됩니다 .
  • for \newcommand\\foo@star시작되고 다음과 같이 정의의 나머지 부분을 사용합니다 \addstarred\foo.

관련 정보