This is a quite common problem in LaTeX because TeX doesn't provide good tools to write a sturdy parser that will understand the difference of a ,
which is supposed to separate two items in a list and the ,
which is just part of a sentence. In fact, most programming languages don't do that and rely on something else to differentiate those, like wrapping a string in "
..."
.
TeX only has macros, and funny ways of grabbing arguments to those macros. If you define a macro with, say, \def\foo[#1]{<use #1>}
, then you must use \foo
with \foo[argument]
, and if you omit either [
or ]
something bad will happen (with "bad" I mean either an error or the argument being something unexpected).
A definition: a delimited argument is any argument (#<number>
) followed by some sequence of at least one token (\def\bar#1\relax{}
, \def\foo[#1]{}
, \def\baz#1xyz{}
are examples of macros whose argument is delimited by \relax
, ]
, and xyz
, respectively).
The delimited argument of a macro will be the shortest brace-balanced list of tokens before the first occurrence of the delimiter. That is, when scanning the delimited argument of a macro, TeX will keep track of how many {
and }
it finds along the way, and will search for first sequence of tokens which matches the argument delimiter, as long as the number of }
matches the number of {
.
Furthermore, if a delimited argument starts with a {
and ends with a }
, the outer layer of braces is dropped. So if you have a macro, say, \def\test[#1]{}
, then using as \test[hello]
or \test[{hello}]
will grab the same hello
as argument. However, if the argument happens to have a ]
, then using \test[he[l]lo]
will only grab he[l
as argument, while using \test[{he[l]lo}]
will grab he[l]lo
.
Here's the paragraph from The TeXbook which explains this (take your time to read it; this paragraph in particular is dense):
How does TeX determine where an argument stops, you ask.
Answer: There are two cases. A delimited parameter is followed
in the <parameter text>
by one or more non-parameter tokens, before
reaching the end of the parameter text or the next parameter token;
in this case the corresponding argument is the shortest (possibly empty)
sequence of tokens with properly nested {...}
groups that is followed in
the input by this particular list of non-parameter tokens. (Category
codes and character codes must both match, and control sequence names
must be the same.) An undelimited parameter is followed immediately
in the <parameter text>
by a parameter token, or it occurs at the very end
of the parameter text; in this case the corresponding argument is the
next nonblank token, unless that token is '{
', when the argument will
be the entire {...}
group that follows. In both cases, if the argument
found in this way has the form '{<nested tokens>}
', where <nested tokens>
stands for any sequence of tokens that is properly nested with
respect to braces, the outermost braces enclosing the argument are removed
and the <nested tokens>
will remain.
(<parameter text>
is what's after the macro name and before a {
in a definition, as in \def\macro<parameter text>{<replacement text>}
, a parameter token is a catcode-6 (usually #
) character)
But what does it all have to do with your problem?
Consider this very simple comma-separated list parser:
% Define
\def\quarkstop{\quarkstop}
\def\csvparse#1{%
\csvparseloop#1,\quarkstop,}
\def\csvparseloop#1,{%
\ifx\quarkstop#1%
\else
\do{#1}%
\expandafter\csvparseloop
\fi}
% Use
\def\do#1{(#1)}
\csvparse{one,{two,2},three}
The \csvparse
macro is just a user-friendly interface to do:
\csvparseloop one,{two,2},three,\quarkstop,
and the \quarkstop
is there so that the code can detect the end of the list.
The \csvparseloop
macro is a delimited macro (defined with \def\csvparseloop#1,{...}
), whose first (and only) argument is delimited by a ,
. So each time it expands, it grabs everything up to the next (brace-balanced) ,
.
In the first iteration, \csvparseloop
sees the ,
after one
and processes one
as argument.
In the second iteration, the ,
after {two
is ignored because the list is {
–}
unbalanced, so TeX grabs the entire {two,2}
and drops the braces, so the argument is two,2
.
In the third iteration the argument is three
, and in the fourth iteration the argument is \quarkstop
, so the loop ends.
In your case, the key-val parser will behave more-or less like in the above example and will understand that each key is delimited by a ,
, and it can't distinguish the ,
which is supposed to separate the key-value pais, and the ,
in the middle of a sentence. That's why you need to wrap the value in braces, so that the parser doesn't get confused.
And of course, this is not David's fault :-)
See also:
firstplural = {Alphas, Bravos, and Charlies (ABCs)}
.,
and splits the argument. It doesn't know which comma means. "hiding" inside braces works because TeX won't grab an argument with unbalanced braces, so it will skip the two commas inAlphas, Bravos, and Charlies
and use the final one as delimiter (otherwise the argument would be{Alphas,
.