Editor that replaces only text inside math environments

I'm writing a document where I had to change all instances of the variable i to x and the document is already considerably long. Is there a editor that will allow me to do this, or in general, replace text inside math environments?

emacs can do this sort of thing fairly easily

(defun change-mathvar (a b)
(interactive "sfrom: \nsto: ")
(beginning-of-buffer)
(while (re-search-forward
"\\\\\(\\|\\\\\$\\|[^\\\$\\?\\|\\\\\|\\\\begin{align}\" nil 1) (query-replace-regexp a b t (point) (progn (re-search-forward "\$$\\\$$\\|\\\\\\]\\|[^\\\\]\\?\\|\\\\\|\\\\end{align}\\)" nil 1) (point)))))


this looks for \$   \begin{align} as math-start. Other environments can be added. Starting from a document such as \documentclass{article} \begin{document} i i aib \[i i aib i i aib $$i i aib$$ \end{document}  then executing M-x change-mathvar the editor will prompt for the old and new names then do a query-replace of the variable names to produce: \documentclass{article} \begin{document} i i aib $x x aib$ i i aib $$x x aib$$ \end{document}  Note it hasn't changed anything out of math and it only changes i where it appears as a complete word, not aib. If you want aib to change as well change the t in the code to nil to make a non-delimited match. • I like this, but one should be aware that it fails on unusual nested constructs such as \( \sum_\text{\( p such that $$2p+1$$ is prime} i^p \) when wishing to change p to q. Jul 31, 2012 at 15:21
• Yes a tradeoff between being smarter and being more complicated. In particular the fact that it doesn't choose the closing delimiter based on which opening delimiter it found makes it easier to trip it up in this way, but simplifies the emacs lisp quite a bit. When doing this though I usually try to make sure the outer loop is "good enough" to cut out the main blocks, and then rely on the fact that the inner-loop is a query-replace so you get to choose and weed out bad cases. (which is why I'd rather do it in emacs than construct a sed expression and edit the whole file without intervention Jul 31, 2012 at 15:26
• I completely agree. Note however in the example I gave, the emacs function only detects the first math p; so you don't get the chance to query replace the other math p's even on a second run. Jul 31, 2012 at 15:45
• yes to make that work you'd need a version that found the outer environment (say $$and then query-replaced all the way to a$$ the version I had would stop at the first \) Jul 31, 2012 at 15:55
• @DavidCarlisle To get a more robust code (with only false positives, no false negatives), there is no need to distinguish the various opening or closing delimiters: the regexp in the (progn ...) construction should count opening and closing delimiters and stop when it finds one extra close. How hard would it be? Aug 12, 2013 at 18:12

My solution using emacs (>=24) and auctex:

(defun latex-replace-in-math ()
"Call query-replace-regexp' with isearch-filter-predicate' set to only match inside LaTeX math environments."
(interactive)
(let ((isearch-filter-predicate
(lambda (BEG END)
(save-excursion (save-match-data (goto-char BEG) (texmathp)))))
(case-fold-search nil))
(call-interactively 'query-replace-regexp)))


This uses texmathp to detect math environments. Undefining case-fold-search has the effect of making the search case sensitive; this usually makes sense for variable symbols.

Usual regular expressions can be used, e.g. searching for \<i\> instead of just i avoids changing \sin to \sxn.

WinEdt is enough:

1. In the "Replace" dialog box, choose the check box "Whole words only" and "Regular expressions".

2. Search for i\E{isMath} and Replace with x.

Then, it works. However, for expression like _i, it will also change to _x which maybe not that you want.

You can also replace text not in math environment by using i\e{isMath}.

I find this trick by searching "Regular Expressions" in the diaglog "WinEdt help". Maybe you find more useful tricks in the help.

I once wrote a perl script to do just that. It's called MathGrep and can be obtained from https://github.com/loopspace/mathgrep. The biggest caveat is that it doesn't recognise dollars (see Are $$and$$ preferable to dollar signs for math mode?), but then I also wrote a script to convert all dollars to $$...$$ and $...$ as well which is at https://github.com/loopspace/debuck.

I'm struggling to think of a use-case where this would beat David's Emacs script though ...

What about to use TeX itself for solving this task? Write the following line at beginning of your document:

\mathcodei=\mathcodex


Vim

In vim with the vimtex plugin,

:%s/beta/\=vimtex#syntax#in_mathzone() ? 'alpha' : submatch(0)/g


will replace beta by alpha only in math zones. The math zones are defined by the vimtex plugin and recognize , \begin{align}}, $, $$ and ,  as you would expect in the following example latex document \documentclass{amsart} \begin{document} This beta won't be replaced. However this one, \beta + \gamma will, so will \(\beta + \gamma$$ and $$\beta + \gamma,$$ \[$$\beta + \gamma,$$$
$$\beta + \gamma,$$
and
\begin{align}
\beta + \gamma.
\end{align}

\end{document}


A bit of explanation. Vim substitute command lets you use an expression instead of a string as the replacement with \=. This is documented for example at https://vim.fandom.com/wiki/Using_an_expression_in_substitute_command. The expression is evaluated at each match (in our example, at each beta in the text file). Then the vimtex plugin provides a function vimtex#syntax#in_mathzone() that checks if the current cursor is in math mode. If that's the case, we return alpha, and otherwise submatch(0) will replace the match by itself and no change will be made.

A caveat is if you would like to use the c flag with many matches. For instance

:%s/M/\=vimtex#syntax#in_mathzone() ? '\mathbf{M}' : submatch(0)/gc


will ask you to confirm the replacement not only in math mode, but also at every occurrences of M in the document including outside math mode, even though confirming the replacement outside math mode will not perform anything.

TeXstudio has a build-in search that allows to search only in certain areas, such as math environment, commands, etc. There are a couple of buttons to the right of the search field, allowing you to customize the search.

If you need more complicated searches, you can also use regular expressions.

Even though the questions has been answered, I add this answer for future reference, for people that like to use TeXstudio.