How can I match the outest bracket and replace it with $$ in vim?

For example:

{a+b>c} --> $a+b>c$

{a+{\int_a^bf(x)dx=\set{a+c}}} --> $a+{\int_a^bf(x)dx=\set{a+c}}$

{a+{b+c}+d} and {e+{f}+g} --> $a+{b+c}+d$ and $a+{f}+g$


By @Ingo Karkat's fascinating answer, I can search and replace correctly on each file. I would like to make this more easy to operate by:

  1. All my file are with filetype tex;
  2. I would like to define a shortcut key to make the search and replace though out the file with ft=tex

How can I do that? (I know this is maybe off topic, and I should solve it by reading vim's doc, but it will take me a lot of time since I am just a begginer user of vim...)

  • Please don't drastically change the subject of your question after you've got several good answers. Mappings are straightforward in Vim; if you need any help please open a new question, and mark this question resolved by accepting the answer that helped you the best. Dec 12 '16 at 7:44

Here's a macro approach that uses the % command to jump to matching curly braces. In contrast to my regular expression solution, this one handles multiple constructs in a line:

Preparation: Don't let search wrap around, the recursive macro would not end and eat into inner braces, too:

:set nowrapscan

Search for and go to the first opening brace:


Clear register q and start recording:


Go to matching closing brace, back to front, replace, back to end, replace, go to next match:


Recursively invoke macro, end macro recording, invoke macro:

  • Note that you can simplify your macro with: %r$<C-O>. to replace one, or %%r$<C-O>.n to replace and search next like you do.
    – nobe4
    Dec 8 '16 at 16:46

As long as there's only one such construct on each line, a simple greedy match (.*) will do. Capture the inner parts (including any {...} inside, up to the last available) in a named capture, and replace with $, captured text, $:


Now, if there can be multiple constructs on a single line (e.g. {a+b>c} and {a+{\int_a^bf(x)dx=\set{a+c}}}), and you want to replace each (i.e. $a+b>c$ and $a+{\int_a^bf(x)dx=\set{a+c}}$, not $a+b>c} and {a+{\int_a^bf(x)dx=\set{a+c}}$, that's a whole different dimension. You would need to match opening and closing curly braces, something which cannot be done with Vim's regular expressions at all.

  • I know that php has Recursive patterns, It seems that there is not correspondence in vim(perl)?
    – van abel
    Dec 8 '16 at 14:59
  • No, unfortunately not. A completely different approach would be a macro using the % command; that one can indeed jump to matching braces. Dec 8 '16 at 15:05

Also, if you like plugins, you can use vim-surround:

cursor here, type: cs{$   (Change Surrounding { by $ )

You have to move yourself to the outer context but once you're there, it's straightforward.

  • 1
    Correct, that basically simplifies the %``r$``r$ part in my macro solution. Dec 8 '16 at 16:14

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.