17

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
$x+y=z$

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

EDIT : egreg's solution works for me :

\documentclass{article} 
\catcode`\$=\active
\gdef$#1${Formula(\detokenize{#1})}
\begin{document}

voila le calcul $3+4=5$

\end{document}

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

\gdef$$#1$${centered-Formula(\detokenize{#1})}

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
  • 8
    Possible, but slightly dangerous: \catcode`$=\active and then \protected\def$#1${foo}
    – egreg
    Jun 15, 2012 at 12:45
  • 4
    Why do you want this? There may be an easier way to achieve what you want.
    – Seamus
    Jun 15, 2012 at 13:01
  • 1
    @Seamus: I actually did it in this answer (because I prefer $...$ to \(...\)). 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` ? 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. Jun 15, 2012 at 19:41

2 Answers 2

21

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

\begingroup
\catcode`\$=\active
\protected\gdef$#1${...}
\endgroup
\AtBeginDocument{\catcode`\$=\active}

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

\documentclass{article}
\usepackage[T1]{fontenc}
\catcode`$=\active
\makeatletter
\protected\def${\@ifnextchar$\@doubledollar\@singledollar}
\def\@doubledollar$#1$${centeredFormula(\detokenize{#1})}
\def\@singledollar#1${Formula(\detokenize{#1})}
\makeatother

\begin{document}

$a+b=b+a$

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

\end{document}
1

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

\documentclass{article}

\ExplSyntaxOn
\char_set_catcode_active:N $
\cs_new:Npn $ { \peek_charcode:NTF $ {\loic_doubledollar:w} {\loic_singledollar:w} }
\cs_new:Npn \loic_doubledollar:w $ #1 $ $ {
    Formula(\detokenize{#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 $ {
    Formula(\detokenize{#1}):
    \c_math_toggle_token #1 \c_math_toggle_token
}
\char_set_catcode_math_toggle:N $
\AtBeginDocument{
    \char_set_catcode_active:N $
}
\ExplSyntaxOff

\begin{document}
$a+b=b+a$
$$a-b\ne b-a$$
\end{document}

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)

\documentclass{article}
\usepackage{amsmath}

\ExplSyntaxOn
% ======== redefine $...$
\char_set_catcode_active:N $
\cs_new:Npn $ #1 $ {
    Formula(\detokenize{#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 \] {
    Formula(\detokenize{#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
\ExplSyntaxOff

\begin{document}
123
$a+b=b+a$
\[a-b\ne b-a\]
and
\begin{align*}
  123 &=456 \\
  456 &=123
\end{align*}
\begin{old-align*}
  xxx123 &=456 \\
  456 &=123
\end{old-align*}

\end{document}

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.

\ExplSyntaxOn
\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
  }
}
\everymath{\mymathprocessor}
\ExplSyntaxOff

$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

$formula$

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.

2

You must log in to answer this question.

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