
두 개의 인수(하나는 선택 사항)를 사용하는 명령을 정의하려고 합니다. 선택적 인수가 제공되지 않으면 선택적 인수에 필수 인수를 사용하고 싶습니다.
예를 들어:
\necommand{\foo}[2][#2]{#1 foo(#2)}
그러면 다음이 반환됩니다.
IN: \foo[hello]{hi} OUT: hello foo(hi)
IN: \foo{hi} OUT: hi foo(hi)
이상적으로는 단순하게 유지하고 패키지 없이 표준 LaTeX를 사용하는 것이 좋을 것입니다. 미리 감사드립니다!
답변1
이에 대한 고전적인 접근 방식은 다음을 사용하는 것입니다 \@dblarg
.
\documentclass{article}
\makeatletter
\newcommand{\foo}{\@dblarg\ah@foo}
\def\ah@foo[#1]#2{#1 foo(#2)}
\makeatother
\begin{document}
No optional argument: \foo{xyz}
Optional argument: \foo[abc]{xyz}
\end{document}
더 xparse
쉽습니다.
\documentclass{article}
\usepackage{xparse}
\NewDocumentCommand{\foo}{om}{%
\IfNoValueTF{#1}{#2}{#1} foo(#2)%
}
\begin{document}
No optional argument: \foo{xyz}
Optional argument: \foo[abc]{xyz}
\end{document}
선택적 인수가 필요할 때마다 를 입력합니다 \IfNoValueTF{#1}{#2}{#1}
.
2017/02/10(또는 그 이후)을 릴리스 한 경우 훨씬 더 매끄러운 방법이 있습니다 xparse
. 선택적 인수는 O
필수 인수 중 하나를 기본값으로 사용할 수 있습니다.
\documentclass{article}
\usepackage{xparse}
\NewDocumentCommand{\foo}{ O{#2} m }{%
#1 foo(#2)%
}
\begin{document}
No optional argument: \foo{xyz}
Optional argument: \foo[abc]{xyz}
\end{document}
\foo
따라서 선택적 인수가 누락된 경우(첫 번째 호출) 필수 인수를 #2
의 값으로도 사용해야 한다고 말하고 있습니다 #1
. 두 번째 호출에서는 선택적 인수가 제공되므로 로 대체됩니다 #1
.
답변2
\NewDocumentCommand
from 을 xparse
사용하면 선택적 인수(o)가 제공되었는지 여부를 확인하는 것이 매우 쉽습니다 \IfValueTF{#1}{}{}
.
그러나 에서는 그렇게 쉽지 않습니다 \newcommand
. 인수 없이 명령을 정의하고 다음 문자가 a인지 \foobar
확인하고 인수를 사용하는 명령 과 필수 인수만 사용하는 또 다른 명령(예: ) 으로 분기합니다 . 이 기술을 '인수 이동'이라고 합니다. 이 방법은 다른 추가 패키지가 필요하지 않으며 LaTeX 핵심 기능을 적용합니다. 유일한 '까다로운' 점은 쌍을 사용하는 것입니다.\@ifnextchar[{}{}
[
[]{}
{}
\makeatletter...\makeatother
\@ifnextchar[
찾고 [
이것이 발견되면 문자는 기본적으로 다시 '이동'되어 \foobar@opt
선택적 인수가 있는 명령의 시작으로 다시 찾을 수 있습니다(실제로는 [
임시 매크로에 저장되고 발견된 true
경우 분기 에 대해 확장됩니다).[
\documentclass{article}
\usepackage{xparse}
\makeatletter
\newcommand{\foobar}{%
\@ifnextchar[{\foobar@opt}{\foobar@noopt}
}{}
\newcommand{\foobar@opt}[2][]{%
#1 foo(#2)%
}
\newcommand{\foobar@noopt}[1]{%
#1 foo(#1)%
}
\makeatother
\NewDocumentCommand{\foo}{om}{%
\IfValueTF{#1}{%
#1 foo(#2)%
}{%
#2 foo(#2)%
}%
}
\begin{document}
\foo[hello]{hi}
\foo{hi}
\foobar[hello]{hi}
\foobar{hi}
\end{document}
답변3
선택적 인수에 기본값을 제공하고 이를 사용하여 처음에 제공되었는지 여부를 조건으로 지정할 수 있습니다.
\documentclass{article}
\newcommand{\foo}[2][\relax]{%
\ifx\relax#1\relax #2\else #1\fi
~foo(#2)%
}
\begin{document}
\foo[hello]{hi}
\foo[]{hi}
\foo{hi}
\end{document}
위에서는 선택적 인수가 \relax
제공되지 않은 경우 기본값을 지정하고 \ifx\relax#1\relax
place #2
또는 를 확인하도록 지정했습니다 #1
. \ifx
다음 두 토큰의 동등성을 비교합니다.
답변4
나는 egreg의 답변, 즉 \@dblarg
.
Werner는 비교 측면에서 "기본값"을 확인할 것을 제안했습니다 \ifx
.
기본값을 확인하는 것은 선택적 인수가 전혀 제공되지 않는 경우와 선택적 인수가 기본값으로 명시적으로 제공되는 경우를 구별하지 않기 때문에 선택적 인수가 제공되었는지 여부를 확인하는 것과 다소 다릅니다.
\ifx
-비교는 다음을 의미합니다.
\ifx
비교는 임시 매크로를 정의하고 비교하여 확장할 수 없는 방식으로 수행됩니다.- 또는
\ifx
-comparison은 기본값을 형성하는 토큰과 실제로 선택적 인수로 제공되는 토큰에 직접 적용됩니다.
후자의 경우 \ifx
-comparison은 기본값으로 사용할 수 있는 항목에 대해 일부 제한을 부과하며 완전히 "방수"되지는 않습니다.
- 기본값은 여러 토큰으로 구성될 수 없습니다.
\ifx
-comparison은 매크로 인수가 아닌 단일 토큰을 비교하므로 인수\ifx
가 두 개 이상의 토큰으로 구성된 극단적인 경우에는 여러 가지 잘못된 방법으로 -comparison을 능가할 수 있습니다.- - 비교
\ifx
는 불균형\else
또는\fi
. \ifx
\let
-기본값 토큰과 동일한 제어 시퀀스 토큰이나 활성 문자 토큰을 사용하여 비교를 능가할 수 있습니다 .
확장 가능한 방식으로 기본값을 확인하는 경로(예: 일부 임시 매크로를 정의하지 않고 \ifx
비교하는 경로)를 사용하는 경우에는 다음을 제안합니다.
기본값으로 "공허함"을 갖고 공허함을 확인합니다.
\documentclass{article} \makeatletter %%========================================================================= %% Paraphernalia: %% \UD@firstoftwo, \UD@secondoftwo %%......................................................................... \newcommand\UD@firstoftwo[2]{#1}% \newcommand\UD@secondoftwo[2]{#2}% %%------------------------------------------------------------------------- %% Check whether argument is empty: %%......................................................................... %% \UD@CheckWhetherNull{<Argument which is to be checked>}% %% {<Tokens to be delivered in case that argument %% which is to be checked is empty>}% %% {<Tokens to be delivered in case that argument %% which is to be checked is not empty>}% %% %% The gist of this macro comes from Robert R. Schneck's \ifempty-macro: %% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J> %% %% A concern in his posting is that the argument is hit with \string %% after some expansions which in edge cases might result in unbalancing %% surrounding \if..\fi-constructs if the macro is used inside of such %% \if..\fi-constructs. %% %% That challenging concern sickened me. ;-) %% %% Therefore I decided to implerment a variant where this cannot happen %% as expansion is forced by \romannumeral: %% %% After the first expansion-step, \string is not applied yet. %% After the second expansion-step, any possibly disturbing remainders %% are already removed due to \romannumeral-expansion. %% %% No eTeX- or whatsoever extensions. No \if.. .Only \romannumeral, %% digit 0, space token for terminating \romannumeral-expansion, %% \string, \expandafter, \UD@firstoftwo, \UD@secondoftwo, {, }. %% %% May 20, 2016 %% %% Ulrich Diez (e-mail: [email protected]) %% \newcommand\UD@CheckWhetherNull[1]{% \romannumeral0\expandafter\UD@secondoftwo\string{\expandafter \UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter \UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter \UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}% \UD@secondoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@firstoftwo}% }% \newcommand{\foo}[2][]{% \UD@CheckWhetherNull{#1}{#2}{#1}~foo(#2)% }% \makeatother \parindent=0ex \parskip=\bigskipamount \begin{document} Empty optional argument or no optional argument will be given---% \verb|\foo{hi}|:\\ \foo{hi} Empty optional argument or no optional argument will be given---% \verb|\foo[]{hi}|:\\ \foo[]{hi} Empty optional argument or no optional argument will be given---% \verb|\foo[{}]{hi}|:\\ \foo[{}]{hi} A nice optional argument will be given---% \verb|\foo[hello]{hi}|:\\ \foo[hello]{hi} \end{document}
또는 구분된 인수를 처리하는 매크로를 통해 기본값을 확인합니다.
\documentclass{article} \makeatletter %%========================================================================= %% Paraphernalia: %% \UD@firstoftwo, \UD@secondoftwo %%......................................................................... \newcommand\UD@firstoftwo[2]{#1}% \newcommand\UD@secondoftwo[2]{#2}% %%------------------------------------------------------------------------- %% Check whether argument is empty: %%......................................................................... %% \UD@CheckWhetherNull{<Argument which is to be checked>}% %% {<Tokens to be delivered in case that argument %% which is to be checked is empty>}% %% {<Tokens to be delivered in case that argument %% which is to be checked is not empty>}% %% %% The gist of this macro comes from Robert R. Schneck's \ifempty-macro: %% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J> %% %% A concern in his posting is that the argument is hit with \string %% after some expansions which in edge cases might result in unbalancing %% surrounding \if..\fi-constructs if the macro is used inside of such %% \if..\fi-constructs. %% %% That challenging concern sickened me. ;-) %% %% Therefore I decided to implerment a variant where this cannot happen %% as expansion is forced by \romannumeral: %% %% After the first expansion-step, \string is not applied yet. %% After the second expansion-step, any possibly disturbing remainders %% are already removed due to \romannumeral-expansion. %% %% No eTeX- or whatsoever extensions. No \if.. .Only \romannumeral, %% digit 0, space token for terminating \romannumeral-expansion, %% \string, \expandafter, \UD@firstoftwo, \UD@secondoftwo, {, }. %% %% May 20, 2016 %% %% Ulrich Diez (e-mail: [email protected]) %% \newcommand\UD@CheckWhetherNull[1]{% \romannumeral0\expandafter\UD@secondoftwo\string{\expandafter \UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter \UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter \UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}% \UD@secondoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@firstoftwo}% }% %%------------------------------------------------------------------------- %% Check whether argument contains no exclamation-mark on top-brace-level: %%......................................................................... %% \UD@CheckWhetherNoExclamationMark{<Argument which is to be checked>}% %% {<Tokens to be delivered in case that %% argument which is to be checked does not contain !>}% %% {<Tokens to be delivered in case that %% argument which is to be checked does contain !>}% \long\def\UD@RemoveToExclamationMark#1!{}% \long\def\UD@CheckWhetherNoExclamationMark#1{% \expandafter\UD@CheckWhetherNull\expandafter{\UD@RemoveToExclamationMark#1!}% }% %%------------------------------------------------------------------------- %% Fork depending on some tokens: %%......................................................................... %%\\CheckWhetherDefault{<Argument which is to be checked>}% %% {<Tokens to be delivered in case argument is "Default value">}% %% {<Tokens to be delivered in case argument is not "Default value">}% %% %% In case <Argument which is to be checked> is neither "case 1" nor %% "case 2" the phrase "Error: Unknown parameter ``<Argument which is %% to be checked>'' to \CheckWhetherDefault." will be delivered. %% \newcommand\@CheckWhetherDefault{}% \long\def\@CheckWhetherDefault% #1!!Default value!#2#3!!!!{#2}% \newcommand\CheckWhetherDefault[1]{% \romannumeral0% \UD@CheckWhetherNoExclamationMark{#1}{% \@CheckWhetherDefault !#1!Default value!{\UD@firstoftwo}% <- #1 is empty. !!#1!{\UD@firstoftwo}% <- #1 = Default value !!Default value!{\UD@secondoftwo}% <- #1 = something else without exclamation mark !!!!% }{\UD@secondoftwo}% <- #1 = something else with exclamation mark }% \makeatother \newcommand{\foo}[2][Default value]{% \CheckWhetherDefault{#1}{#2}% {#1}% ~foo(#2)% }% \parindent=0ex \parskip=\bigskipamount \begin{document} ``Default value'' or empty optional argument or no optional argument will be given---% \verb|\foo{hi}|:\\ \foo{hi} ``Default value'' or empty optional argument or no optional argument will be given---% \verb|\foo[Default value]{hi}|:\\ \foo[Default value]{hi} ``Default value'' or empty optional argument or no optional argument will be given---% \verb|\foo[]{hi}|:\\ \foo[]{hi} ``Default value'' or empty optional argument or no optional argument will be given---% \verb|\foo[{}]{hi}|:\\ \foo[{}]{hi} A nice optional argument will be given---% \verb|\foo[hello]{hi}|:\\ \foo[hello]{hi} \end{document}
\ifx
임시 매크로를 정의하고 비교하는 지루하고 확장 불가능한 경로를 사용할 수도 있습니다 .
\documentclass{article}
\makeatletter
\newcommand{\foo}[2][Default value]{%
\begingroup
\def\mytempa{#1}%
\def\mytempb{Default value}%
\ifx\mytempa\mytempb
\expandafter\endgroup\expandafter\@secondoftwo
\else
\expandafter\@firstofone
\fi
{%
\def\mytempb{}%
\expandafter\endgroup\ifx\mytempa\mytempb
\expandafter\@secondoftwo
\else
\expandafter\@firstoftwo
\fi
{#1}%
}{#2}~foo(#2)%
}%
\makeatother
\parindent=0ex
\parskip=\bigskipamount
\begin{document}
``Default value'' or empty optional argument or no optional argument will be given---%
\verb|\foo{hi}|:\\
\foo{hi}
``Default value'' or empty optional argument or no optional argument will be given---%
\verb|\foo[Default value]{hi}|:\\
\foo[Default value]{hi}
``Default value'' or empty optional argument or no optional argument will be given---%
\verb|\foo[]{hi}|:\\
\foo[]{hi}
``Default value'' or empty optional argument or no optional argument will be given---%
\verb|\foo[{}]{hi}|:\\
\foo[{}]{hi}
A nice optional argument will be given---%
\verb|\foo[hello]{hi}|:\\
\foo[hello]{hi}
\end{document}
이전에 말했듯이: 일반적인/일반적인 상황에서 나는 \@dblarg
이러한 접근 방식보다 확실히 -thing을 선호합니다.