인수를 취하는 매크로를 생성하는 매크로 정의

인수를 취하는 매크로를 생성하는 매크로 정의

나는 꽤 오랫동안 라텍스를 사용해왔지만 아주 기본적인 것만 사용했습니다. 가능하면 패키지를 사용하려고 노력합니다. 나는 이제 내 라텍스 문서를 더 깔끔하게 만들기 위해 몇 가지 코드를 직접 작성하려고 합니다. 이것이 내가 달성하고 싶은 것입니다:

내가 정의할 때:

\symb{flow}{f_#1^#2}[a,b]

사용할 수 있기를 원합니다

\flow        % outputs $f_a^b$
\flow[x,y]   % outputs $f_x^y$

인덱스 수는 반드시 2일 필요는 없으며, 1일 수도 있고, 2보다 클 수도 있습니다.

다음은 내가 지금 가지고 있는 것입니다:

\NewDocumentCommand{\symb}{m m m}
{ \expandafter\NewDocumentCommand\csname#1\endcsname{>{\SplitList{,}}O{#3}}
    { 
        % Not sure what I need to write here
    }
}

기본적으로 저는 변수의 쉼표로 구분된 인덱스인 선택적 인수를 취하는 \symb{flow}{f_#1^#2}[a,b]매크로를 정의하는 데 사용할 수 있기를 원합니다 . \flow선택적 인수가 제공되지 않는 경우 기본 인덱스(이 경우 a, b)가 사용됩니다.

Python에서는 다음과 같이 작성됩니다.

def symb(expr, default):
    def fn(*args):
        if len(args) == 0:
            return expr % args
        else:
            return expr % default

    return fn

flow = symb('$f_%s^%s$', (a, b))

flow()        % outputs $f_a^b$
flow(x, y)    % outputs $f_x^y$

답변1

할 수는 있지만 Python을 LaTeX 프로그래밍 모델로 삼아서는 안 됩니다.

LaTeX에서는 인수가 중괄호로 묶여 있으며 쉼표 목록으로 대체될 수 없습니다.

어쨌든, 여기에는 템플릿에 임의 개수의 인수가 포함된 구현이 있습니다(물론 원하는 개수를 지정해야 합니다).

\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\symb}{mmmm}
 {% #1=name of command to define, #2=number of args, #3=template, #4=default

  % define the internal version
  \cs_new_protected:cn { kelvin_symb_#1:\prg_replicate:nn{#2}{n} } { #3 }

  % define the external version
  \exp_args:Nc \NewDocumentCommand { #1 } { O{#4} }
   {
    \__kelvin_symb_do:nnx { #1 } { #2 } { \clist_map_function:nN { ##1 } \__kelvin_symb_brace:n }
   }
 }

\cs_new:Nn \__kelvin_symb_do:nnn
 {
  \use:c { kelvin_symb_#1:\prg_replicate:nn{#2}{n} } #3
 }
\cs_generate_variant:Nn \__kelvin_symb_do:nnn { nnx }

\cs_new:Nn \__kelvin_symb_brace:n { {#1} }

\ExplSyntaxOff

\symb{flow}{2}{f_{#1}^{#2}}{a,b}
\symb{foo}{4}{\int_{#1}^{#2}#3\,d#4}{0,1,x,x}

\begin{document}

$\flow$

$\flow[x,y]$

$\foo$

$\foo[a,b,f(x),x]$

\end{document}

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

코드에 대한 몇 가지 단어가 더 있습니다. 먼저 쉬운 것:

\exp_args:Nc \NewDocumentCommand { #1 } { O{#4} }

expl3의 버전 입니다

\expandafter\NewDocumentCommand\csname#1\endcsname { O{#4 } }

선호되어야합니다.

다음으로 작동 방식에 대한 설명입니다 \symb. 먼저 선언된 만큼의 인수를 사용하여 내부 함수를 정의합니다. 대체 텍스트는 지정된 템플릿에 의해 제공됩니다. 따라서 \symb{flow}{2}{f_{#1}^{#2}}{a,b}정의

\kelvin_symb_flow:nn { f_{#1}^{#2} }

메모. _의 범위에 있는 문자 로 \ExplSyntaxOn선언 \symb{flow}{2}{...}{...}되어 있으므로 문제가 없습니다 .밖의그 범위.

\flow그런 다음 선택적 인수를 사용하여 사용자 수준 명령을 정의합니다 . 기본값은 의 네 번째 인수입니다 \symb. 이 명령은 를 통해 이전에 정의된 함수를 간접적으로 호출합니다 \__kelvin_symb_do:nnx.

첫 번째 인수는 이 경우 이고 flow, 두 번째 인수는 인수 수입니다. 그 목적은 내부 함수를 호출할 수 있는 것입니다. 마지막 인수는 쉼표 목록(기본값 또는 에 선택적 인수로 제공되는 목록 \flow)이지만 중괄호 항목 목록을 생성하도록 전처리됩니다.

일반 버전은 \__kelvin_symb_do:nnn내부 함수를 형성 \kelvin_symb_flow:nn하고 세 번째 인수를 해제합니다. 그러나 우리는 그 변형을 사용하고 있습니다. 언제

\clist_map_function:nN { #1 } \__kelvin_symb_brace:n

변형으로 인해 완전히 확장되었으며 x, 적용 a,b하면 {a}{b}. 따라서 우리는 결국

\kelvin_symb_flow:nn { a } { b }

LaTeX는 평소와 같이 f_{a}^{b}.

답변2

예를 들어 다음을 사용할 수 있습니다.

\def\sdef#1{\expandafter\def\csname#1\endcsname}

\def\symb#1#2[#3,#4]{%
  \sdef{#1}{\expandafter\futurelet\expandafter\next\csname#1:a\endcsname}%
  \sdef{#1:a}{\ifx\next[\csname#1:b\expandafter\endcsname 
              \else     \csname#1:b\endcsname[#3,#4]\fi}%
  \sdef{#1:b}[##1,##2]{#2}%
}  

\symb{flow}{f_#1^#2}[a,b]

$\flow$ and $\flow[x,y]$.

이 매크로의 두 번째 버전은 주석의 요구 사항을 구현합니다.

\def\sdef#1{\expandafter\def\csname#1\endcsname}
\def\addto#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}

\def\symb#1#2[#3]{%
  \sdef{#1}{\expandafter\futurelet\expandafter\next\csname#1:a\endcsname}%
  \sdef{#1:a}{\ifx\next[\csname#1:b\expandafter\endcsname 
              \else     \csname#1:c\endcsname #3,,,,,,,,\end \fi}%
  \sdef{#1:b}[##1]{\def\paramslistA{#3,}\def\paramslistB{}\setparams ##1,\end,
     \csname#1:c\expandafter\endcsname \paramslistB,,,,,,,,\end}%
  \sdef{#1:c}##1,##2,##3,##4,##5,##6,##7,##8,##9\end{#2}%
}
\def\setparams #1,{\ifx\end#1%
      \expandafter\addto\expandafter\paramslistB\expandafter{\paramslistA}%
   \else \expandafter \setparamslist \paramslistA \end #1,%
   \expandafter\setparams\fi}
\def\setparamslist#1,#2\end#3,{\def\paramslistA{#2}\addto\paramslistB{#3,}}

\symb{flow}{f_#1^#2}[a,b]

\symb{test}{test: 1=#1, 2=#2, 3=#3, 4=#4}[a,b,c,d]

$\flow$ and $\flow[x,y]$.

\test

\test[mmm]

\test[x,y,z]

이 솔루션은 egreg의 솔루션과 다릅니다. expl3 cmplicated 매크로가 필요하지 않으며 TeX 프리미티브만 사용됩니다.

답변3

이는 wipet과 유사하지만 댓글에서 논의된 것처럼 Symb에 대한 인수를 필수로 만듭니다.

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

\documentclass{article}

\def\symb#1#2#3{%
\expandafter\def\csname x#1\endcsname##1##2{#2}%
\expandafter\newcommand\csname #1\endcsname[1][#3]{%
  \expandafter\splitcomma\csname x#1\endcsname ##1\relax}}

\def\splitcomma#1#2,#3\relax{#1{#2}{#3}}

\begin{document}

\symb{flow}{f_#1^#2}{a,b}


$\flow$

$\flow[x,y]$

\end{document}

그리고 인수 목록에 여러 항목(최대 8개)을 허용하는 버전입니다.

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

\documentclass{article}

\def\symb#1#2#3{%
\expandafter\def\csname x#1\endcsname##1##2##3##4##5##6##7##8##9{#2}%
\expandafter\newcommand\csname #1\endcsname[1][#3]{%
  \expandafter\splitcomma\csname x#1\endcsname ##1,,,,,,,,,,\relax}}


\def\splitcomma#1#2,#3,#4,#5,#6,#7,#8,#9\relax{#1{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}\relax}

\begin{document}

\symb{flow}{f_#1^#2}{a,b}

\symb{flowb}{f_#1^#2g_#3^#4}{a,b,c,d}


$\flow$

$\flow[x,y]$

$\flowb$

$\flowb[x,y,w,z]$

\end{document}

관련 정보