How to define a command with two optional arguments?
Clash Royale CLAN TAG#URR8PPP
up vote
7
down vote
favorite
I would like to have a single command that can take either 1, 2, or 3 arguments and do something different for each number of arguments.
ca -> C_a
cab -> C_a^[b]
cabc -> C_a,c^[b]
Since Latex has no command overloading, I decided that optional arguments are good enough:
ca -> C_a
c[b]a -> C_a^[b]
c[c][b]a -> C_a,c^[b]
I found that this great answer using xparse
might do exactly what I need. However his answer works only for 2 optional arguments. He mentions how to extend it to any number of arguments, but I couldn't figure it out. I tried:
usepackagexparse
....
DeclareDocumentCommand c o o m %
IfNoValueTF #1 %
IfNoValueTF #2 %
C_#3%
%
C_#3^[#2]%
%
%
C_#2, #3^[#1]%
%
$ca c[b]a c[c][b]a$
But it seems that I cannot get the branch with two arguments to work:
What am I doing wrong?
macros xparse optional-arguments
add a comment |Â
up vote
7
down vote
favorite
I would like to have a single command that can take either 1, 2, or 3 arguments and do something different for each number of arguments.
ca -> C_a
cab -> C_a^[b]
cabc -> C_a,c^[b]
Since Latex has no command overloading, I decided that optional arguments are good enough:
ca -> C_a
c[b]a -> C_a^[b]
c[c][b]a -> C_a,c^[b]
I found that this great answer using xparse
might do exactly what I need. However his answer works only for 2 optional arguments. He mentions how to extend it to any number of arguments, but I couldn't figure it out. I tried:
usepackagexparse
....
DeclareDocumentCommand c o o m %
IfNoValueTF #1 %
IfNoValueTF #2 %
C_#3%
%
C_#3^[#2]%
%
%
C_#2, #3^[#1]%
%
$ca c[b]a c[c][b]a$
But it seems that I cannot get the branch with two arguments to work:
What am I doing wrong?
macros xparse optional-arguments
In LaTeX you don't need braces with undelimited single-token-arguments. Thus: How to handlecabc
? Shall this meanc
has one arg and the one-arg-call toc
is trailed by lettersb
andc
which do not form args ofc
? Shall this mean a three-argument-call toc
with two args just not being nested in braces as braces are not really needed with single-token-arguments? You can check if a single-argument-macro's arg in turn consists of three or two or one brace-delimited arguments, i.e.,cabc
, but then you need to specify behavior for other cases and spaces as well.
– Ulrich Diez
Aug 31 at 16:56
add a comment |Â
up vote
7
down vote
favorite
up vote
7
down vote
favorite
I would like to have a single command that can take either 1, 2, or 3 arguments and do something different for each number of arguments.
ca -> C_a
cab -> C_a^[b]
cabc -> C_a,c^[b]
Since Latex has no command overloading, I decided that optional arguments are good enough:
ca -> C_a
c[b]a -> C_a^[b]
c[c][b]a -> C_a,c^[b]
I found that this great answer using xparse
might do exactly what I need. However his answer works only for 2 optional arguments. He mentions how to extend it to any number of arguments, but I couldn't figure it out. I tried:
usepackagexparse
....
DeclareDocumentCommand c o o m %
IfNoValueTF #1 %
IfNoValueTF #2 %
C_#3%
%
C_#3^[#2]%
%
%
C_#2, #3^[#1]%
%
$ca c[b]a c[c][b]a$
But it seems that I cannot get the branch with two arguments to work:
What am I doing wrong?
macros xparse optional-arguments
I would like to have a single command that can take either 1, 2, or 3 arguments and do something different for each number of arguments.
ca -> C_a
cab -> C_a^[b]
cabc -> C_a,c^[b]
Since Latex has no command overloading, I decided that optional arguments are good enough:
ca -> C_a
c[b]a -> C_a^[b]
c[c][b]a -> C_a,c^[b]
I found that this great answer using xparse
might do exactly what I need. However his answer works only for 2 optional arguments. He mentions how to extend it to any number of arguments, but I couldn't figure it out. I tried:
usepackagexparse
....
DeclareDocumentCommand c o o m %
IfNoValueTF #1 %
IfNoValueTF #2 %
C_#3%
%
C_#3^[#2]%
%
%
C_#2, #3^[#1]%
%
$ca c[b]a c[c][b]a$
But it seems that I cannot get the branch with two arguments to work:
What am I doing wrong?
macros xparse optional-arguments
asked Aug 30 at 17:34
Martin Drozdik
82931527
82931527
In LaTeX you don't need braces with undelimited single-token-arguments. Thus: How to handlecabc
? Shall this meanc
has one arg and the one-arg-call toc
is trailed by lettersb
andc
which do not form args ofc
? Shall this mean a three-argument-call toc
with two args just not being nested in braces as braces are not really needed with single-token-arguments? You can check if a single-argument-macro's arg in turn consists of three or two or one brace-delimited arguments, i.e.,cabc
, but then you need to specify behavior for other cases and spaces as well.
– Ulrich Diez
Aug 31 at 16:56
add a comment |Â
In LaTeX you don't need braces with undelimited single-token-arguments. Thus: How to handlecabc
? Shall this meanc
has one arg and the one-arg-call toc
is trailed by lettersb
andc
which do not form args ofc
? Shall this mean a three-argument-call toc
with two args just not being nested in braces as braces are not really needed with single-token-arguments? You can check if a single-argument-macro's arg in turn consists of three or two or one brace-delimited arguments, i.e.,cabc
, but then you need to specify behavior for other cases and spaces as well.
– Ulrich Diez
Aug 31 at 16:56
In LaTeX you don't need braces with undelimited single-token-arguments. Thus: How to handle
cabc
? Shall this mean c
has one arg and the one-arg-call to c
is trailed by letters b
and c
which do not form args of c
? Shall this mean a three-argument-call to c
with two args just not being nested in braces as braces are not really needed with single-token-arguments? You can check if a single-argument-macro's arg in turn consists of three or two or one brace-delimited arguments, i.e., cabc
, but then you need to specify behavior for other cases and spaces as well.– Ulrich Diez
Aug 31 at 16:56
In LaTeX you don't need braces with undelimited single-token-arguments. Thus: How to handle
cabc
? Shall this mean c
has one arg and the one-arg-call to c
is trailed by letters b
and c
which do not form args of c
? Shall this mean a three-argument-call to c
with two args just not being nested in braces as braces are not really needed with single-token-arguments? You can check if a single-argument-macro's arg in turn consists of three or two or one brace-delimited arguments, i.e., cabc
, but then you need to specify behavior for other cases and spaces as well.– Ulrich Diez
Aug 31 at 16:56
add a comment |Â
2 Answers
2
active
oldest
votes
up vote
7
down vote
accepted
You should start from examining #2
rather than #1
, because #2
only can have a value if #1
has, too.
documentclassarticle
usepackagexparse
NewDocumentCommand C o o m %
IfNoValueTF#2
%
IfNoValueTF #1
%
C_#3%
%
C_#3^[#1]%
%
%
C_#3, #1^[#2]%
%
begindocument
$Ca quad C[b]a quad C[c][b]a$
enddocument
And don't use DeclareDocumentCommand
to override the meaning of c
: you'll regret it when you have to cite some French or Turkish author with “ç†in their name.
add a comment |Â
up vote
1
down vote
You wish to define a macro c
. But c
is already defined in LaTeX.
Therefore I will henceforth not refer to the macro in question as c
.
Instead I will refer to the macro in question as macroc
.
Are you aware that in TeX/LaTeX undelimited arguments consisting of a single token don't need to be nested in braces?
After defining newcommandfoo[1]This is argument 1: #1.
,foob
will yield the same result asfoo b
.
After defining newcommandbar[2]This is argument 1: #1. This is argument 2: #2.
, the following calls will all yield the same result:barab
bar ab
bar ab
bar ab
bara b
bar a b
bar a b
bar a b
This is because
- you don't need braces when undelimited arguments consist of a single token.
- (La)TeX does discard space tokens preceding undelimited arguments.
When called as macrocabc
—how shall macroc
"know" whether the user intends to have c
as macroc
's third argument which consists of the single token c
or whether the user intends to have macroc
called with only two arguments, namely a
and b
while c
shall not be considered a third argument?
The situation is ambiguous.
You can turn the situation into something unambiguous by having macroc
process only one undelimited argument and having macroc
check whether that argument in turn is of one of the patterns
⟨argument 1⟩
⟨argument 1⟩⟨argument 2⟩
⟨argument 1⟩⟨argument 2⟩⟨argument 3⟩
and having macroc
act accordingly in case one of these patterns is detected and having macroc
deliver an error-message otherwise.
I.e.,
macroc⟨argument 1⟩
macroc⟨argument 1⟩⟨argument 2⟩
macroc⟨argument 1⟩⟨argument 2⟩⟨argument 3⟩
With the example below, macroc
does process one undelimited argument.
Syntax: macroc⟨argument⟩
.
In case ⟨argument⟩
is of pattern ⟨argument 1⟩
,macrocatonearg⟨argument 1⟩
will be carried out.
In case ⟨argument⟩
is of pattern ⟨argument 1⟩⟨argument 2⟩
, macrocattwoargs⟨argument 1⟩⟨argument 2⟩
will be carried out.
In case ⟨argument⟩
is of pattern ⟨argument 1⟩⟨argument 2⟩⟨argument 3⟩
, macrocatthreeargs⟨argument 1⟩⟨argument 2⟩⟨argument 3⟩
will be carried out.
In all other cases an error-message will inform the user about a syntax-error.
Thus you can do, e.g., :
macroca
macrocab
macrocabc
documentclassarticle
makeatletter
%%=============================================================================
%% Paraphernalia:
%% UD@firstoftwo, UD@secondoftwo,
%% UD@gobble, UD@gobbletwo, UD@gobblethree
%% UD@CheckWhetherNull, UD@CheckWhetherBrace,
%%=============================================================================
newcommandUD@firstoftwo[2]#1%
newcommandUD@secondoftwo[2]#2%
newcommandUD@gobble[1]%
newcommandUD@gobbletwo[2]%
newcommandUD@gobblethree[3]%
%%-----------------------------------------------------------------------------
%% 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>
newcommandUD@CheckWhetherNull[1]%
romannumeral0expandafterUD@secondoftwostringexpandafter
UD@secondoftwoexpandafterexpandafterstring#1expandafter
UD@secondoftwostringexpandafterUD@firstoftwoexpandafterexpandafter
UD@secondoftwostringexpandafterexpandafterUD@firstoftwo %
UD@secondoftwoexpandafterexpandafterUD@firstoftwo UD@firstoftwo%
%
%%-----------------------------------------------------------------------------
%% Check whether argument's first token is a catcode-1-character
%%.............................................................................
%% UD@CheckWhetherBrace<Argument which is to be checked>%
%% <Tokens to be delivered in case that argument
%% which is to be checked has leading
%% catcode-1-token>%
%% <Tokens to be delivered in case that argument
%% which is to be checked has no leading
%% catcode-1-token>%
newcommandUD@CheckWhetherBrace[1]%
romannumeral0expandafterUD@secondoftwoexpandafterexpandafter%
string#1.expandafterUD@firstoftwoexpandafterexpandafter
UD@secondoftwostringexpandafterexpandafterUD@firstoftwo %
UD@firstoftwoexpandafterexpandafterUD@firstoftwo UD@secondoftwo%
%
%%=============================================================================
%% macroc for processing one argument within which
%% you may have one or two or three brace-nested arguments:
%%-----------------------------------------------------------------------------
newcommandmacrocatonearg[1]C_#1%
newcommandmacrocattwoargs[2]C_#1^[#2]%
newcommandmacrocatthreeargs[3]C_#1,#3^[#2]%
newcommandmacrocatsyntaxerror%
@latex@errorIncorrect SyntaxSpecify either one or two or three arguments that are nested in braces.%
%
newcommandmacroc[1]%
UD@CheckWhetherBrace#1%
expandafterUD@CheckWhetherNullexpandafterUD@gobble#1%
macrocatonearg#1%
%
expandafterUD@CheckWhetherBraceexpandafterUD@gobble#1%
expandafterUD@CheckWhetherNullexpandafterUD@gobbletwo#1%
macrocattwoargs#1%
%
expandafterUD@CheckWhetherBraceexpandafterUD@gobbletwo#1%
expandafterUD@CheckWhetherNullexpandafterUD@gobblethree#1%
macrocatthreeargs#1%
macrocatsyntaxerror%
macrocatsyntaxerror%
%
macrocatsyntaxerror%
%
macrocatsyntaxerror%
%
makeatother
begindocument
verb|$macroca$|: $macroca$ bigskip
verb|$macrocab$|: $macrocab$ bigskip
verb|$macrocabc$|: $macrocabc$ bigskip
% Syntax-errors:
%
% $macrocabcd$
%
% $macroc a$
%
% $macroca b$
%
% $macroca$
%
% $macroc$
enddocument
add a comment |Â
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
7
down vote
accepted
You should start from examining #2
rather than #1
, because #2
only can have a value if #1
has, too.
documentclassarticle
usepackagexparse
NewDocumentCommand C o o m %
IfNoValueTF#2
%
IfNoValueTF #1
%
C_#3%
%
C_#3^[#1]%
%
%
C_#3, #1^[#2]%
%
begindocument
$Ca quad C[b]a quad C[c][b]a$
enddocument
And don't use DeclareDocumentCommand
to override the meaning of c
: you'll regret it when you have to cite some French or Turkish author with “ç†in their name.
add a comment |Â
up vote
7
down vote
accepted
You should start from examining #2
rather than #1
, because #2
only can have a value if #1
has, too.
documentclassarticle
usepackagexparse
NewDocumentCommand C o o m %
IfNoValueTF#2
%
IfNoValueTF #1
%
C_#3%
%
C_#3^[#1]%
%
%
C_#3, #1^[#2]%
%
begindocument
$Ca quad C[b]a quad C[c][b]a$
enddocument
And don't use DeclareDocumentCommand
to override the meaning of c
: you'll regret it when you have to cite some French or Turkish author with “ç†in their name.
add a comment |Â
up vote
7
down vote
accepted
up vote
7
down vote
accepted
You should start from examining #2
rather than #1
, because #2
only can have a value if #1
has, too.
documentclassarticle
usepackagexparse
NewDocumentCommand C o o m %
IfNoValueTF#2
%
IfNoValueTF #1
%
C_#3%
%
C_#3^[#1]%
%
%
C_#3, #1^[#2]%
%
begindocument
$Ca quad C[b]a quad C[c][b]a$
enddocument
And don't use DeclareDocumentCommand
to override the meaning of c
: you'll regret it when you have to cite some French or Turkish author with “ç†in their name.
You should start from examining #2
rather than #1
, because #2
only can have a value if #1
has, too.
documentclassarticle
usepackagexparse
NewDocumentCommand C o o m %
IfNoValueTF#2
%
IfNoValueTF #1
%
C_#3%
%
C_#3^[#1]%
%
%
C_#3, #1^[#2]%
%
begindocument
$Ca quad C[b]a quad C[c][b]a$
enddocument
And don't use DeclareDocumentCommand
to override the meaning of c
: you'll regret it when you have to cite some French or Turkish author with “ç†in their name.
answered Aug 30 at 17:48


egreg
681k8318083056
681k8318083056
add a comment |Â
add a comment |Â
up vote
1
down vote
You wish to define a macro c
. But c
is already defined in LaTeX.
Therefore I will henceforth not refer to the macro in question as c
.
Instead I will refer to the macro in question as macroc
.
Are you aware that in TeX/LaTeX undelimited arguments consisting of a single token don't need to be nested in braces?
After defining newcommandfoo[1]This is argument 1: #1.
,foob
will yield the same result asfoo b
.
After defining newcommandbar[2]This is argument 1: #1. This is argument 2: #2.
, the following calls will all yield the same result:barab
bar ab
bar ab
bar ab
bara b
bar a b
bar a b
bar a b
This is because
- you don't need braces when undelimited arguments consist of a single token.
- (La)TeX does discard space tokens preceding undelimited arguments.
When called as macrocabc
—how shall macroc
"know" whether the user intends to have c
as macroc
's third argument which consists of the single token c
or whether the user intends to have macroc
called with only two arguments, namely a
and b
while c
shall not be considered a third argument?
The situation is ambiguous.
You can turn the situation into something unambiguous by having macroc
process only one undelimited argument and having macroc
check whether that argument in turn is of one of the patterns
⟨argument 1⟩
⟨argument 1⟩⟨argument 2⟩
⟨argument 1⟩⟨argument 2⟩⟨argument 3⟩
and having macroc
act accordingly in case one of these patterns is detected and having macroc
deliver an error-message otherwise.
I.e.,
macroc⟨argument 1⟩
macroc⟨argument 1⟩⟨argument 2⟩
macroc⟨argument 1⟩⟨argument 2⟩⟨argument 3⟩
With the example below, macroc
does process one undelimited argument.
Syntax: macroc⟨argument⟩
.
In case ⟨argument⟩
is of pattern ⟨argument 1⟩
,macrocatonearg⟨argument 1⟩
will be carried out.
In case ⟨argument⟩
is of pattern ⟨argument 1⟩⟨argument 2⟩
, macrocattwoargs⟨argument 1⟩⟨argument 2⟩
will be carried out.
In case ⟨argument⟩
is of pattern ⟨argument 1⟩⟨argument 2⟩⟨argument 3⟩
, macrocatthreeargs⟨argument 1⟩⟨argument 2⟩⟨argument 3⟩
will be carried out.
In all other cases an error-message will inform the user about a syntax-error.
Thus you can do, e.g., :
macroca
macrocab
macrocabc
documentclassarticle
makeatletter
%%=============================================================================
%% Paraphernalia:
%% UD@firstoftwo, UD@secondoftwo,
%% UD@gobble, UD@gobbletwo, UD@gobblethree
%% UD@CheckWhetherNull, UD@CheckWhetherBrace,
%%=============================================================================
newcommandUD@firstoftwo[2]#1%
newcommandUD@secondoftwo[2]#2%
newcommandUD@gobble[1]%
newcommandUD@gobbletwo[2]%
newcommandUD@gobblethree[3]%
%%-----------------------------------------------------------------------------
%% 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>
newcommandUD@CheckWhetherNull[1]%
romannumeral0expandafterUD@secondoftwostringexpandafter
UD@secondoftwoexpandafterexpandafterstring#1expandafter
UD@secondoftwostringexpandafterUD@firstoftwoexpandafterexpandafter
UD@secondoftwostringexpandafterexpandafterUD@firstoftwo %
UD@secondoftwoexpandafterexpandafterUD@firstoftwo UD@firstoftwo%
%
%%-----------------------------------------------------------------------------
%% Check whether argument's first token is a catcode-1-character
%%.............................................................................
%% UD@CheckWhetherBrace<Argument which is to be checked>%
%% <Tokens to be delivered in case that argument
%% which is to be checked has leading
%% catcode-1-token>%
%% <Tokens to be delivered in case that argument
%% which is to be checked has no leading
%% catcode-1-token>%
newcommandUD@CheckWhetherBrace[1]%
romannumeral0expandafterUD@secondoftwoexpandafterexpandafter%
string#1.expandafterUD@firstoftwoexpandafterexpandafter
UD@secondoftwostringexpandafterexpandafterUD@firstoftwo %
UD@firstoftwoexpandafterexpandafterUD@firstoftwo UD@secondoftwo%
%
%%=============================================================================
%% macroc for processing one argument within which
%% you may have one or two or three brace-nested arguments:
%%-----------------------------------------------------------------------------
newcommandmacrocatonearg[1]C_#1%
newcommandmacrocattwoargs[2]C_#1^[#2]%
newcommandmacrocatthreeargs[3]C_#1,#3^[#2]%
newcommandmacrocatsyntaxerror%
@latex@errorIncorrect SyntaxSpecify either one or two or three arguments that are nested in braces.%
%
newcommandmacroc[1]%
UD@CheckWhetherBrace#1%
expandafterUD@CheckWhetherNullexpandafterUD@gobble#1%
macrocatonearg#1%
%
expandafterUD@CheckWhetherBraceexpandafterUD@gobble#1%
expandafterUD@CheckWhetherNullexpandafterUD@gobbletwo#1%
macrocattwoargs#1%
%
expandafterUD@CheckWhetherBraceexpandafterUD@gobbletwo#1%
expandafterUD@CheckWhetherNullexpandafterUD@gobblethree#1%
macrocatthreeargs#1%
macrocatsyntaxerror%
macrocatsyntaxerror%
%
macrocatsyntaxerror%
%
macrocatsyntaxerror%
%
makeatother
begindocument
verb|$macroca$|: $macroca$ bigskip
verb|$macrocab$|: $macrocab$ bigskip
verb|$macrocabc$|: $macrocabc$ bigskip
% Syntax-errors:
%
% $macrocabcd$
%
% $macroc a$
%
% $macroca b$
%
% $macroca$
%
% $macroc$
enddocument
add a comment |Â
up vote
1
down vote
You wish to define a macro c
. But c
is already defined in LaTeX.
Therefore I will henceforth not refer to the macro in question as c
.
Instead I will refer to the macro in question as macroc
.
Are you aware that in TeX/LaTeX undelimited arguments consisting of a single token don't need to be nested in braces?
After defining newcommandfoo[1]This is argument 1: #1.
,foob
will yield the same result asfoo b
.
After defining newcommandbar[2]This is argument 1: #1. This is argument 2: #2.
, the following calls will all yield the same result:barab
bar ab
bar ab
bar ab
bara b
bar a b
bar a b
bar a b
This is because
- you don't need braces when undelimited arguments consist of a single token.
- (La)TeX does discard space tokens preceding undelimited arguments.
When called as macrocabc
—how shall macroc
"know" whether the user intends to have c
as macroc
's third argument which consists of the single token c
or whether the user intends to have macroc
called with only two arguments, namely a
and b
while c
shall not be considered a third argument?
The situation is ambiguous.
You can turn the situation into something unambiguous by having macroc
process only one undelimited argument and having macroc
check whether that argument in turn is of one of the patterns
⟨argument 1⟩
⟨argument 1⟩⟨argument 2⟩
⟨argument 1⟩⟨argument 2⟩⟨argument 3⟩
and having macroc
act accordingly in case one of these patterns is detected and having macroc
deliver an error-message otherwise.
I.e.,
macroc⟨argument 1⟩
macroc⟨argument 1⟩⟨argument 2⟩
macroc⟨argument 1⟩⟨argument 2⟩⟨argument 3⟩
With the example below, macroc
does process one undelimited argument.
Syntax: macroc⟨argument⟩
.
In case ⟨argument⟩
is of pattern ⟨argument 1⟩
,macrocatonearg⟨argument 1⟩
will be carried out.
In case ⟨argument⟩
is of pattern ⟨argument 1⟩⟨argument 2⟩
, macrocattwoargs⟨argument 1⟩⟨argument 2⟩
will be carried out.
In case ⟨argument⟩
is of pattern ⟨argument 1⟩⟨argument 2⟩⟨argument 3⟩
, macrocatthreeargs⟨argument 1⟩⟨argument 2⟩⟨argument 3⟩
will be carried out.
In all other cases an error-message will inform the user about a syntax-error.
Thus you can do, e.g., :
macroca
macrocab
macrocabc
documentclassarticle
makeatletter
%%=============================================================================
%% Paraphernalia:
%% UD@firstoftwo, UD@secondoftwo,
%% UD@gobble, UD@gobbletwo, UD@gobblethree
%% UD@CheckWhetherNull, UD@CheckWhetherBrace,
%%=============================================================================
newcommandUD@firstoftwo[2]#1%
newcommandUD@secondoftwo[2]#2%
newcommandUD@gobble[1]%
newcommandUD@gobbletwo[2]%
newcommandUD@gobblethree[3]%
%%-----------------------------------------------------------------------------
%% 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>
newcommandUD@CheckWhetherNull[1]%
romannumeral0expandafterUD@secondoftwostringexpandafter
UD@secondoftwoexpandafterexpandafterstring#1expandafter
UD@secondoftwostringexpandafterUD@firstoftwoexpandafterexpandafter
UD@secondoftwostringexpandafterexpandafterUD@firstoftwo %
UD@secondoftwoexpandafterexpandafterUD@firstoftwo UD@firstoftwo%
%
%%-----------------------------------------------------------------------------
%% Check whether argument's first token is a catcode-1-character
%%.............................................................................
%% UD@CheckWhetherBrace<Argument which is to be checked>%
%% <Tokens to be delivered in case that argument
%% which is to be checked has leading
%% catcode-1-token>%
%% <Tokens to be delivered in case that argument
%% which is to be checked has no leading
%% catcode-1-token>%
newcommandUD@CheckWhetherBrace[1]%
romannumeral0expandafterUD@secondoftwoexpandafterexpandafter%
string#1.expandafterUD@firstoftwoexpandafterexpandafter
UD@secondoftwostringexpandafterexpandafterUD@firstoftwo %
UD@firstoftwoexpandafterexpandafterUD@firstoftwo UD@secondoftwo%
%
%%=============================================================================
%% macroc for processing one argument within which
%% you may have one or two or three brace-nested arguments:
%%-----------------------------------------------------------------------------
newcommandmacrocatonearg[1]C_#1%
newcommandmacrocattwoargs[2]C_#1^[#2]%
newcommandmacrocatthreeargs[3]C_#1,#3^[#2]%
newcommandmacrocatsyntaxerror%
@latex@errorIncorrect SyntaxSpecify either one or two or three arguments that are nested in braces.%
%
newcommandmacroc[1]%
UD@CheckWhetherBrace#1%
expandafterUD@CheckWhetherNullexpandafterUD@gobble#1%
macrocatonearg#1%
%
expandafterUD@CheckWhetherBraceexpandafterUD@gobble#1%
expandafterUD@CheckWhetherNullexpandafterUD@gobbletwo#1%
macrocattwoargs#1%
%
expandafterUD@CheckWhetherBraceexpandafterUD@gobbletwo#1%
expandafterUD@CheckWhetherNullexpandafterUD@gobblethree#1%
macrocatthreeargs#1%
macrocatsyntaxerror%
macrocatsyntaxerror%
%
macrocatsyntaxerror%
%
macrocatsyntaxerror%
%
makeatother
begindocument
verb|$macroca$|: $macroca$ bigskip
verb|$macrocab$|: $macrocab$ bigskip
verb|$macrocabc$|: $macrocabc$ bigskip
% Syntax-errors:
%
% $macrocabcd$
%
% $macroc a$
%
% $macroca b$
%
% $macroca$
%
% $macroc$
enddocument
add a comment |Â
up vote
1
down vote
up vote
1
down vote
You wish to define a macro c
. But c
is already defined in LaTeX.
Therefore I will henceforth not refer to the macro in question as c
.
Instead I will refer to the macro in question as macroc
.
Are you aware that in TeX/LaTeX undelimited arguments consisting of a single token don't need to be nested in braces?
After defining newcommandfoo[1]This is argument 1: #1.
,foob
will yield the same result asfoo b
.
After defining newcommandbar[2]This is argument 1: #1. This is argument 2: #2.
, the following calls will all yield the same result:barab
bar ab
bar ab
bar ab
bara b
bar a b
bar a b
bar a b
This is because
- you don't need braces when undelimited arguments consist of a single token.
- (La)TeX does discard space tokens preceding undelimited arguments.
When called as macrocabc
—how shall macroc
"know" whether the user intends to have c
as macroc
's third argument which consists of the single token c
or whether the user intends to have macroc
called with only two arguments, namely a
and b
while c
shall not be considered a third argument?
The situation is ambiguous.
You can turn the situation into something unambiguous by having macroc
process only one undelimited argument and having macroc
check whether that argument in turn is of one of the patterns
⟨argument 1⟩
⟨argument 1⟩⟨argument 2⟩
⟨argument 1⟩⟨argument 2⟩⟨argument 3⟩
and having macroc
act accordingly in case one of these patterns is detected and having macroc
deliver an error-message otherwise.
I.e.,
macroc⟨argument 1⟩
macroc⟨argument 1⟩⟨argument 2⟩
macroc⟨argument 1⟩⟨argument 2⟩⟨argument 3⟩
With the example below, macroc
does process one undelimited argument.
Syntax: macroc⟨argument⟩
.
In case ⟨argument⟩
is of pattern ⟨argument 1⟩
,macrocatonearg⟨argument 1⟩
will be carried out.
In case ⟨argument⟩
is of pattern ⟨argument 1⟩⟨argument 2⟩
, macrocattwoargs⟨argument 1⟩⟨argument 2⟩
will be carried out.
In case ⟨argument⟩
is of pattern ⟨argument 1⟩⟨argument 2⟩⟨argument 3⟩
, macrocatthreeargs⟨argument 1⟩⟨argument 2⟩⟨argument 3⟩
will be carried out.
In all other cases an error-message will inform the user about a syntax-error.
Thus you can do, e.g., :
macroca
macrocab
macrocabc
documentclassarticle
makeatletter
%%=============================================================================
%% Paraphernalia:
%% UD@firstoftwo, UD@secondoftwo,
%% UD@gobble, UD@gobbletwo, UD@gobblethree
%% UD@CheckWhetherNull, UD@CheckWhetherBrace,
%%=============================================================================
newcommandUD@firstoftwo[2]#1%
newcommandUD@secondoftwo[2]#2%
newcommandUD@gobble[1]%
newcommandUD@gobbletwo[2]%
newcommandUD@gobblethree[3]%
%%-----------------------------------------------------------------------------
%% 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>
newcommandUD@CheckWhetherNull[1]%
romannumeral0expandafterUD@secondoftwostringexpandafter
UD@secondoftwoexpandafterexpandafterstring#1expandafter
UD@secondoftwostringexpandafterUD@firstoftwoexpandafterexpandafter
UD@secondoftwostringexpandafterexpandafterUD@firstoftwo %
UD@secondoftwoexpandafterexpandafterUD@firstoftwo UD@firstoftwo%
%
%%-----------------------------------------------------------------------------
%% Check whether argument's first token is a catcode-1-character
%%.............................................................................
%% UD@CheckWhetherBrace<Argument which is to be checked>%
%% <Tokens to be delivered in case that argument
%% which is to be checked has leading
%% catcode-1-token>%
%% <Tokens to be delivered in case that argument
%% which is to be checked has no leading
%% catcode-1-token>%
newcommandUD@CheckWhetherBrace[1]%
romannumeral0expandafterUD@secondoftwoexpandafterexpandafter%
string#1.expandafterUD@firstoftwoexpandafterexpandafter
UD@secondoftwostringexpandafterexpandafterUD@firstoftwo %
UD@firstoftwoexpandafterexpandafterUD@firstoftwo UD@secondoftwo%
%
%%=============================================================================
%% macroc for processing one argument within which
%% you may have one or two or three brace-nested arguments:
%%-----------------------------------------------------------------------------
newcommandmacrocatonearg[1]C_#1%
newcommandmacrocattwoargs[2]C_#1^[#2]%
newcommandmacrocatthreeargs[3]C_#1,#3^[#2]%
newcommandmacrocatsyntaxerror%
@latex@errorIncorrect SyntaxSpecify either one or two or three arguments that are nested in braces.%
%
newcommandmacroc[1]%
UD@CheckWhetherBrace#1%
expandafterUD@CheckWhetherNullexpandafterUD@gobble#1%
macrocatonearg#1%
%
expandafterUD@CheckWhetherBraceexpandafterUD@gobble#1%
expandafterUD@CheckWhetherNullexpandafterUD@gobbletwo#1%
macrocattwoargs#1%
%
expandafterUD@CheckWhetherBraceexpandafterUD@gobbletwo#1%
expandafterUD@CheckWhetherNullexpandafterUD@gobblethree#1%
macrocatthreeargs#1%
macrocatsyntaxerror%
macrocatsyntaxerror%
%
macrocatsyntaxerror%
%
macrocatsyntaxerror%
%
makeatother
begindocument
verb|$macroca$|: $macroca$ bigskip
verb|$macrocab$|: $macrocab$ bigskip
verb|$macrocabc$|: $macrocabc$ bigskip
% Syntax-errors:
%
% $macrocabcd$
%
% $macroc a$
%
% $macroca b$
%
% $macroca$
%
% $macroc$
enddocument
You wish to define a macro c
. But c
is already defined in LaTeX.
Therefore I will henceforth not refer to the macro in question as c
.
Instead I will refer to the macro in question as macroc
.
Are you aware that in TeX/LaTeX undelimited arguments consisting of a single token don't need to be nested in braces?
After defining newcommandfoo[1]This is argument 1: #1.
,foob
will yield the same result asfoo b
.
After defining newcommandbar[2]This is argument 1: #1. This is argument 2: #2.
, the following calls will all yield the same result:barab
bar ab
bar ab
bar ab
bara b
bar a b
bar a b
bar a b
This is because
- you don't need braces when undelimited arguments consist of a single token.
- (La)TeX does discard space tokens preceding undelimited arguments.
When called as macrocabc
—how shall macroc
"know" whether the user intends to have c
as macroc
's third argument which consists of the single token c
or whether the user intends to have macroc
called with only two arguments, namely a
and b
while c
shall not be considered a third argument?
The situation is ambiguous.
You can turn the situation into something unambiguous by having macroc
process only one undelimited argument and having macroc
check whether that argument in turn is of one of the patterns
⟨argument 1⟩
⟨argument 1⟩⟨argument 2⟩
⟨argument 1⟩⟨argument 2⟩⟨argument 3⟩
and having macroc
act accordingly in case one of these patterns is detected and having macroc
deliver an error-message otherwise.
I.e.,
macroc⟨argument 1⟩
macroc⟨argument 1⟩⟨argument 2⟩
macroc⟨argument 1⟩⟨argument 2⟩⟨argument 3⟩
With the example below, macroc
does process one undelimited argument.
Syntax: macroc⟨argument⟩
.
In case ⟨argument⟩
is of pattern ⟨argument 1⟩
,macrocatonearg⟨argument 1⟩
will be carried out.
In case ⟨argument⟩
is of pattern ⟨argument 1⟩⟨argument 2⟩
, macrocattwoargs⟨argument 1⟩⟨argument 2⟩
will be carried out.
In case ⟨argument⟩
is of pattern ⟨argument 1⟩⟨argument 2⟩⟨argument 3⟩
, macrocatthreeargs⟨argument 1⟩⟨argument 2⟩⟨argument 3⟩
will be carried out.
In all other cases an error-message will inform the user about a syntax-error.
Thus you can do, e.g., :
macroca
macrocab
macrocabc
documentclassarticle
makeatletter
%%=============================================================================
%% Paraphernalia:
%% UD@firstoftwo, UD@secondoftwo,
%% UD@gobble, UD@gobbletwo, UD@gobblethree
%% UD@CheckWhetherNull, UD@CheckWhetherBrace,
%%=============================================================================
newcommandUD@firstoftwo[2]#1%
newcommandUD@secondoftwo[2]#2%
newcommandUD@gobble[1]%
newcommandUD@gobbletwo[2]%
newcommandUD@gobblethree[3]%
%%-----------------------------------------------------------------------------
%% 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>
newcommandUD@CheckWhetherNull[1]%
romannumeral0expandafterUD@secondoftwostringexpandafter
UD@secondoftwoexpandafterexpandafterstring#1expandafter
UD@secondoftwostringexpandafterUD@firstoftwoexpandafterexpandafter
UD@secondoftwostringexpandafterexpandafterUD@firstoftwo %
UD@secondoftwoexpandafterexpandafterUD@firstoftwo UD@firstoftwo%
%
%%-----------------------------------------------------------------------------
%% Check whether argument's first token is a catcode-1-character
%%.............................................................................
%% UD@CheckWhetherBrace<Argument which is to be checked>%
%% <Tokens to be delivered in case that argument
%% which is to be checked has leading
%% catcode-1-token>%
%% <Tokens to be delivered in case that argument
%% which is to be checked has no leading
%% catcode-1-token>%
newcommandUD@CheckWhetherBrace[1]%
romannumeral0expandafterUD@secondoftwoexpandafterexpandafter%
string#1.expandafterUD@firstoftwoexpandafterexpandafter
UD@secondoftwostringexpandafterexpandafterUD@firstoftwo %
UD@firstoftwoexpandafterexpandafterUD@firstoftwo UD@secondoftwo%
%
%%=============================================================================
%% macroc for processing one argument within which
%% you may have one or two or three brace-nested arguments:
%%-----------------------------------------------------------------------------
newcommandmacrocatonearg[1]C_#1%
newcommandmacrocattwoargs[2]C_#1^[#2]%
newcommandmacrocatthreeargs[3]C_#1,#3^[#2]%
newcommandmacrocatsyntaxerror%
@latex@errorIncorrect SyntaxSpecify either one or two or three arguments that are nested in braces.%
%
newcommandmacroc[1]%
UD@CheckWhetherBrace#1%
expandafterUD@CheckWhetherNullexpandafterUD@gobble#1%
macrocatonearg#1%
%
expandafterUD@CheckWhetherBraceexpandafterUD@gobble#1%
expandafterUD@CheckWhetherNullexpandafterUD@gobbletwo#1%
macrocattwoargs#1%
%
expandafterUD@CheckWhetherBraceexpandafterUD@gobbletwo#1%
expandafterUD@CheckWhetherNullexpandafterUD@gobblethree#1%
macrocatthreeargs#1%
macrocatsyntaxerror%
macrocatsyntaxerror%
%
macrocatsyntaxerror%
%
macrocatsyntaxerror%
%
makeatother
begindocument
verb|$macroca$|: $macroca$ bigskip
verb|$macrocab$|: $macrocab$ bigskip
verb|$macrocabc$|: $macrocabc$ bigskip
% Syntax-errors:
%
% $macrocabcd$
%
% $macroc a$
%
% $macroca b$
%
% $macroca$
%
% $macroc$
enddocument
edited Sep 3 at 16:02
answered Aug 31 at 17:42
Ulrich Diez
3,250414
3,250414
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f448542%2fhow-to-define-a-command-with-two-optional-arguments%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
In LaTeX you don't need braces with undelimited single-token-arguments. Thus: How to handle
cabc
? Shall this meanc
has one arg and the one-arg-call toc
is trailed by lettersb
andc
which do not form args ofc
? Shall this mean a three-argument-call toc
with two args just not being nested in braces as braces are not really needed with single-token-arguments? You can check if a single-argument-macro's arg in turn consists of three or two or one brace-delimited arguments, i.e.,cabc
, but then you need to specify behavior for other cases and spaces as well.– Ulrich Diez
Aug 31 at 16:56