# Why doesn't this macro work well with french option of babel?

The following code, inspired by this answer, procudes an undesired result when the french option of babel is selected. However, it works fine with the english option!

Can anyone explain this to me, and find a way so that it works well with the french option?

\documentclass[12pt]{article}
\usepackage[french]{babel}
%\usepackage[english]{babel}
\usepackage{amsmath}

\def\matr#1{\def\matrL{}\matrA#1\end}
\def\matrA#1{\ifx\end#1\begin{pmatrix}\matrL\end{pmatrix}\else
\expandafter\matrA\fi
}

\begin{document}
$\matr{ a, b ; c, d }$
\end{document}


With the french option, I get this: , while this should give me this: , as it does with english option.

• try to add [shorthands=off] to the babel invocation --- wild guess about some active character Mar 10 '21 at 15:36
• @campa Yep, I see. The manual says that : ; ! ? are made active. Surely they should revert to the original meaning in math mode? (edit: I see the manual says that you have to use {,} in math mode. Quite invasive...) Mar 10 '21 at 15:40
• @Rmano Yes, they should... Mar 10 '21 at 15:45
• @Rmano The thing with the comma is unrelated. The comma isn't active but is a \mathpunct, which is fine if you don't use it as decimal separator. Enclosing it in braces is addressed also in the TeXbook. Mar 10 '21 at 16:03
• Be aware that \addto is already defined by babel and it's not good policy to redefine it. Avoid \def, generally speaking. Mar 10 '21 at 17:02

In order to ensure the French typographic conventions some characters, including the semi-colon ;, are made active when the language is selected at \begin{document}.

When you type your definitions in the preamble the colon has still \catcode 12 (other), and so the definition of \matrA will check #1 against a colon with category code 12. However, at \begin{document} the colon is made active (category code 13) and the test will always fail.

Short of deactivating the babel shorthands in math mode, I see two quick ways out of this: either you define the macros with an active colon (which will work only when you are using french and fail otherwise), or you replace the \ifx test by \if, which tests only character code but not category code.

\documentclass[12pt]{article}
\usepackage[french]{babel}
\usepackage{amsmath}

% Avoid redefining babel's own \addto
% (thanks to egreg for bringing this to my attention)

% Works only when french is loaded
% \begingroup
% \catcode\;=\active
% \gdef\matr#1{\def\matrL{}\matrA#1\end}
% \gdef\matrA#1{\ifx\end#1\begin{pmatrix}\matrL\end{pmatrix}\else
%    \expandafter\matrA\fi
% }
% \endgroup

\newcommand*{\matr}[1]{\def\matrL{}\matrA#1\end}
\newcommand*{\matrA}[1]{%
\ifx\end#1\begin{pmatrix}\matrL\end{pmatrix}\else
\expandafter\matrA\fi
}

\begin{document}

$\matr{ a , b ; c , d }$

\end{document}


yields the desired output

• Incredible! I didn't know this property of ; in French mode! Very nice, thanks! Mar 10 '21 at 16:05
• On the other hand, this will not work if used without babel-french. Mar 10 '21 at 21:20
• @egreg True, of course, but both the question and the answer specifically identify french as a crucial part of the problem. And the commented alternative works in any case (though maybe better with wipet's addition). I forgot to warn the OP against accepting the answer to soon; I usually do that. I'll add a comment. Mar 10 '21 at 21:29

The problem is that the semicolon is active in babel-french.

Here's a solution that replaces semicolons with any category code with semicolons of category code 12, so the “usual” splitting into rows and then processing each row can be used.

If you use the code when the semicolon is not active, there will be no problem, because no replacement would be made.

\documentclass[12pt]{article}
\usepackage[T1]{fontenc}
\usepackage[french]{babel}
\usepackage{amsmath}

\ExplSyntaxOn
\NewDocumentCommand{\matr}{O{p}m}
{
\watson_matrix:nn { #1 } { #2 }
}

\cs_new_protected:Nn \watson_matrix:nn
{
\tl_set:Nn \l_tmpa_tl { #2 }
\regex_replace_all:nnN { ; } { \cO; } \l_tmpa_tl
\seq_set_split:NnV \l_tmpa_seq { ; } \l_tmpa_tl
\begin{#1matrix}
\seq_map_function:NN \l_tmpa_seq \__watson_matrix_row:n
\end{#1matrix}
}
\cs_new_protected:Nn \__watson_matrix_row:n
{
\seq_set_split:Nnn \l_tmpb_seq { , } { #1 }
\seq_use:Nn \l_tmpb_seq { & }
\\
}

\ExplSyntaxOff

\begin{document}

$\matr{ a, b ; c, d }\qquad \matr[b]{1,2,3;4,5,6}$

\end{document}


Just for convenience, I added support for different fences. With \matr[]{1,2;3,4} you get no fence at all.

1. \addto is already defined by babel in a different way, but it does the same job. Overwriting this definition can lead to errors. You could just use \addto as provided by babel, but I can't recommend it, because it performs global definitions. You can avoid the issue by loading etoolbox and use its \appto command.

2. \cr should not be used inside any matrix environment defined by amsmath. Rows should be ended by \\ which does much more than \cr.

3. Don't use \def with LaTeX unless you precisely know what you're doing, in particular know that the control sequence you're going to define is not yet defined or you know why you want to redefine it. In your case, \def\matrL is good, because it's a scratch macro that's going to be redefined several times. But \def\addto... isn't good at all.

• +1 for "\cr should not be used inside any matrix environment defined by amsmath". :-)
– Mico
Mar 10 '21 at 22:18

In order to make the macro more resistant from catcode changing you can change \ifx primitive to \if primitive and add \string:

\def\matrA#1{\ifx\end#1\begin{pmatrix}\matrL\end{pmatrix}\else
\expandafter\matrA\fi
}


Here's a LuaLaTeX solution. It consists of 2 LaTeX utility macros, \pmatr and \bmatr, and a trio of Lua functions that do (almost) all of the work.

The yellow bars in the following screenshot show that ; (and !) continue to have their special meaning (of being separated by whitespace from the preceding material).

Observe also that this approach works whether or not ; is an "active" character.

\documentclass[12pt]{article}
\usepackage[french]{babel}
\usepackage{amsmath} % for 'pmatrix' and 'bmatrix' environments

\usepackage{luacode} % for 'luacode' env. and '\luastring' macro
\begin{luacode}

function change_chars ( s ) -- replace ';" and "," characters
s = s:gsub ( ";" , "\\\\" )
s = s:gsub ( "," , "&" )
return  s
end
function pmatr ( s )
tex.sprint ( "\\begin{pmatrix}" .. change_chars(s) .. "\\end{pmatrix}" )
end
function bmatr ( s )
tex.sprint ( "\\begin{bmatrix}" .. change_chars(s) .. "\\end{bmatrix}" )
end

\end{luacode}

% Define a couple of utility or "front end" LaTeX macros
\newcommand\pmatr[1]{\directlua{pmatr("#1")}}
\newcommand\bmatr[1]{\directlua{bmatr("#1")}}

\begin{document}
$\pmatr{ a, b ; c, d } \quad \bmatr{ a, b ; c, d ; e , f}$\quad bonjour; bonsoir!
\end{document}
`