4

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\addto#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}
\def\matr#1{\def\matrL{}\matrA#1\end}
\def\matrA#1{\ifx\end#1\begin{pmatrix}\matrL\end{pmatrix}\else 
   \ifx,#1\addto\matrL{&}\else
   \ifx;#1\addto\matrL{\cr}\else
   \addto\matrL{#1}\fi\fi
   \expandafter\matrA\fi
}

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

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

6
  • try to add [shorthands=off] to the babel invocation --- wild guess about some active character
    – Rmano
    Mar 10, 2021 at 15:36
  • 1
    @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...)
    – Rmano
    Mar 10, 2021 at 15:40
  • 1
    @Rmano Yes, they should...
    – campa
    Mar 10, 2021 at 15:45
  • 1
    @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.
    – campa
    Mar 10, 2021 at 16:03
  • 2
    Be aware that \addto is already defined by babel and it's not good policy to redefine it. Avoid \def, generally speaking.
    – egreg
    Mar 10, 2021 at 17:02

4 Answers 4

4

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)
\newcommand*{\myaddto}[2]{\expandafter\def\expandafter#1\expandafter{#1#2}}

% 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 
%    \ifx,#1\myaddto\matrL{&}\else
%    \ifx;#1\myaddto\matrL{\\}\else
%    \myaddto\matrL{#1}\fi\fi
%    \expandafter\matrA\fi
% }
% \endgroup

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

\begin{document}

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

\end{document}

yields the desired output enter image description here

4
  • Incredible! I didn't know this property of ; in French mode! Very nice, thanks!
    – Watson
    Mar 10, 2021 at 16:05
  • 1
    On the other hand, this will not work if used without babel-french.
    – egreg
    Mar 10, 2021 at 21:20
  • 1
    @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.
    – campa
    Mar 10, 2021 at 21:29
  • @campa See also the comments I added to my answer.
    – egreg
    Mar 10, 2021 at 21:34
5

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.

enter image description here

Some comments on your code.

  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
  • 1
    +1 for "\cr should not be used inside any matrix environment defined by amsmath". :-)
    – Mico
    Mar 10, 2021 at 22:18
4

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 
   \if,\string#1\addto\matrL{&}\else
   \if;\string#1\addto\matrL{\cr}\else
   \addto\matrL{#1}\fi\fi
   \expandafter\matrA\fi
}
3

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.

enter image description here

\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}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.