I want to capture the math mode through a redefinition of the $. I thought about something like

\def$#1${here was a formula}
% to test

I would expect "here was a formula" as output. Is it possible ?

EDIT : egreg's solution works for me :


voila le calcul $3+4=5$


But i would like also to redefine the double dollar $$ ...$$. If i define additionally :


then the following works :

voila un calcul centré $$x+y=z$$

but I can't use the single dollar anymore: $3+4=5$ fails now to compile.

Question : how can I have both $...$ and $$...$$ available ?

  • 8
    Possible, but slightly dangerous: \catcode`$=\active and then \protected\def$#1${foo}
    – egreg
    Commented Jun 15, 2012 at 12:45
  • 4
    Why do you want this? There may be an easier way to achieve what you want.
    – Seamus
    Commented Jun 15, 2012 at 13:01
  • 1
    @Seamus: I actually did it in this answer (because I prefer $...$ to \(...\)). Commented Jun 15, 2012 at 13:23
  • 1
    @egreg. I know, I can put the \catcode in a group, and this will have no effect outside. But if i don't, how can I cancel the effect of '\catcode$=\active' later on in the document ? And for which reason did you put a \protected` ? Commented Jun 15, 2012 at 19:19
  • 2
    Well, my question about how to cancel the effect, was just a subsidiary question, because to frightened me with "dangerous". But your answer is perfect for me. What i want to do : i want to export a tex document into some xml file. For this, i need to capture the maths formulas, a make \write of the \detokenize of the content of the math environment. With your catcode trick, it works. Commented Jun 15, 2012 at 19:41

2 Answers 2


You can, but there's no guarantee that it will work in all situations:


For $$...$$, with even less guarantees:




$$a-b\ne b-a$$


This is the same as the other answer's solution, but implemented in expl3:


\char_set_catcode_active:N $
\cs_new:Npn $ { \peek_charcode:NTF $ {\loic_doubledollar:w} {\loic_singledollar:w} }
\cs_new:Npn \loic_doubledollar:w $ #1 $ $ {
    \c_math_toggle_token \c_math_toggle_token #1
    \c_math_toggle_token \c_math_toggle_token
\cs_new:Npn \loic_singledollar:w #1 $ {
    \c_math_toggle_token #1 \c_math_toggle_token
\char_set_catcode_math_toggle:N $
    \char_set_catcode_active:N $

$$a-b\ne b-a$$

Extra: handle \[, \begin{align*} etc.

Unfortunately, align* environment uses align under the hood, so it's dangerous to redefine align. Similarly, redefining equation* breaks \[... \].

Nevertheless, it's not recommended to use $$...$$ in LaTeX, \[...\] is more recommended, refer to Why is \[ ... \] preferable to $$ ... $$? .

Furthermore, it may be desirable to redefine several other math environments such as \begin{tikzcd}..\end{tikzcd}, \begin{align*}..\end{align*}, etc.

A full list can be found in texdoc amsldoc (plus the deprecated eqnarray, and the environments \begin{math}, \begin{displaymath}):

amsldoc extract

This is an example of redefining \[...\] and \begin{align*}...\end{align*}: (\(...\) is not handled)


% ======== redefine $...$
\char_set_catcode_active:N $
\cs_new:Npn $ #1 $ {
    \c_math_toggle_token #1 \c_math_toggle_token
\char_set_catcode_other:N $
\AtBeginDocument{ \char_set_catcode_active:N \$ }
% ======== redefine \[...\]
\cs_new_eq:NN \lois__old_open_square_bracket: \[
\cs_gset:Npn \[ #1 \] {
    \lois__old_open_square_bracket: #1 \]
% ======== redefine align*
\ProvideDocumentCommand \NewEnvironmentCopy {mm} {  % lines taken from https://tex.stackexchange.com/a/680717/250119, can be deleted if LaTeX version is new enough
    \expandafter \NewCommandCopy \csname#1\expandafter\endcsname \csname#2\endcsname
    \expandafter \NewCommandCopy \csname end#1\expandafter\endcsname \csname end#2\endcsname }
\ProvideDocumentCommand \RenewEnvironmentCopy {mm} {
    \expandafter \RenewCommandCopy \csname#1\expandafter\endcsname \csname#2\endcsname
    \expandafter \RenewCommandCopy \csname end#1\expandafter\endcsname \csname end#2\endcsname }

\NewEnvironmentCopy{old-align*}{align*} % backup the old definition

%do nothing: fine -- \RenewDocumentEnvironment{align*}{}{\csname old-align*\endcsname}{\csname endold-align*\endcsname}
%insert something at the start of the environment: fine -- \RenewDocumentEnvironment{align*}{}{\csname old-align*\endcsname xxx}{\csname endold-align*\endcsname}
% this may appear to work well, but will silently use wrong spacing! -- \RenewDocumentEnvironment{align*}{}{\csname old-align*\endcsname}{xxx\csname endold-align*\endcsname}
\RenewDocumentEnvironment{align*}{b}{Formula: \begin{old-align*}#1\end{old-align*}}{}
% ======== done

\[a-b\ne b-a\]
  123 &=456 \\
  456 &=123
  xxx123 &=456 \\
  456 &=123


Alternative solution that is flaky and not recommended

You may think of using \everymath to automatically insert the command whenever $ is used automatically. Nevertheless, this will break a lot of things that uses math mode under the hood e.g. \textsuperscript, \underline, \(...\), etc.

\quark_new:N \qmymathpreserve  % variable name does not conform to expl3 recommendation!
\cs_set:Npn \my_token_if_eq_meaning:nNTF #1 {\token_if_eq_meaning:NNTF #1}  % (remove braces around #1.) (note that this will not work properly when #1 is empty.)
\cs_generate_variant:Nn \my_token_if_eq_meaning:nNTF {xNTF}
\cs_new:Npn \mymathprocessor #1 $ {
  \my_token_if_eq_meaning:xNTF {\tl_head:n {#1}} \qmymathpreserve {
    \tl_tail:n {#1} $  % preserve the old behavior
  } {
    $  % close the math environment first...
    #1 ~  % then print as text  (put ~ here because space at the start of a line doesn't work)
    $\qmymathpreserve a^2$  % add another math formula for demonstration

$this is actually text$

$\qmymathpreserve a^2+b^2$

As you can tell, the following code

$\qmymathpreserve formula$

will render as a "normal" math formula, while the following code


will preprocess the formula with the processor. In this case the processor is expandable.

You can even add additional text outside a math environment, as demonstrated by the example above (but you still an empty math formula).

Note that \tl_head:n will return empty if the input is empty, which breaks \my_token_if_eq_meaning:nNTF.

For $$...$$ use \everydisplay.

Note: even if the formula is closed immediately, there is still an empty math formula, which is a larger problem in display mode.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .