13

I have a file, containing some lines like this: aaa bbb (ccc) ddd.

Now I want to replace the pair of brackets by a pair of square brackets to make this line become aaa bbb [ccc] ddd.

I think that \ze and/or \zs might be used but I don't know how.

8 Answers 8

14

You can do it in a single substitute command like this

:s/(\(.*\))/[\1]/

The \( and \) mark the regex subexpression that matches everything inside the ( and ) in the input line. In the replacement, the \1 stands for whatever the first (in this case the only) marked subexpression matched.

In words you might describe the substitute command as: look for a "(" followed by anything followed by ")". Replace that by "[" followed by the same "anything" followed by "]".

5
  • 2
    Welcome to this site AndyB! And great answer!
    – statox
    Oct 28, 2019 at 9:05
  • 2
    Worth noting that this will change a line like aaa (bbb) ccc (ddd) to aaa [bbb) ccc (ddd] not the aaa [bbb] ccc (ddd) that one might initially expect. Oct 29, 2019 at 1:37
  • 1
    greedy .* should be change to non-greedy .\{-}
    – Maxim Kim
    Oct 29, 2019 at 6:21
  • 1
    @MaximKim This would still replace ((aaa (bbb) ccc) ddd with [(aaa (bbb] ccc) ddd. Better use the vim-surround plugin as suggested by D. Ben Knoble. That way only nested brackets are replaced.
    – Tim
    Oct 29, 2019 at 7:53
  • @MichaelAnderson how can that be avoided using :s?
    – minseong
    Mar 27, 2021 at 12:31
19

With tpope/vim-surround, this is a simple

cs)]

away in Normal mode.

  • cs is the "change-surrounding" operator
  • ) is the "target"
  • ] is the replacement
5
  • 1
    The accepted answer (to use a substitution) is perfectly correct, but I would absolutely recommend vim-surround, as it makes operations like this utterly trivial. Changing surrounding characters, removing them, adding them, all very useful. This is a very good plugin to consider installing.
    – Dave Kerr
    Nov 3, 2019 at 15:56
  • cs id a bad abbreviation since cscope uses the same and is more common. Dec 1, 2020 at 15:22
  • @GreenTree cscope uses ex commands, no? :cscope? What I am showing are normal-mode keystrokes. At any rate, comments are for clarification or feedback; if you have an opinion on the plugin I mentioned, take it up with the author (Tim Pope), not here.
    – D. Ben Knoble
    Dec 1, 2020 at 15:26
  • Thanks for clarification, but you could point that in you answer that the command should be run in normal mode, then I would not leave any comments. So "here" is for clear and complete answers with complete in-page explanations. Dec 1, 2020 at 15:34
  • is it possible to make it work in VS Code?
    – Xitcod13
    Jul 6, 2023 at 19:15
8

You can use this simple :s command (or better two :))

:s/(/[/g
:s/)/]/g

You can even do it in one run, you you define your replacements first like this:

:let replace={'(':'[', ')':']'}
:s/[()]/\=replace[submatch(0)]/g

Here we first define a dictionary with the keys of what you want to have replaced. So we need a key ( with the value [ since that is the replacement char you want. Also we want the key ) wit the value ].

Then we can use a sub-replacement-special to have the replacement character dynamically evaluated using the provided replace dictionary.

5

If that your cursor is on the left brace that you want to change:

%r]^Or[

If your cursor is on the right brace:

%r[^Or]

Basically, ask vim to find the matching brace, change it, then jump back to the first brace and change it too.

If your cursor is near enough to one of the braces you want to change, then you can do much as the above but double the initial %:

%%r]^Or[

Or

%%r[^Or]

This works across multiple lines, and with nested brackets.

You may even find it works with xml or html, depending on various things.

1
  • I'm on my phone so I may be daft but I couldn't get this to work, however this does: %r]``r[
    – 110100100
    Dec 4, 2020 at 20:10
0

No need for a plugin, just apply the substitution command:

:%s/(\(\([^()]\|\n\)*\))/[\1]/g

Notes

  • Supports multiple matches per line: (aa) (bb) -> [aa] [bb]
  • Supports multi-line content: (aa \n bb) -> [aa \n bb]
  • Supports nested parenthesis: ((aa)) -> ([aa])
  • Doesn't change unmatched characters: a) (b) -> a) [b]
  • However it needs to be applied multiple times manually to substitute the outer parenthesis: ([aa]) -> [[aa]].

Breakdown of the command

  • :%s/ for all lines, substitute the pattern:
  • ( start pattern with opening parenthesis
  • outer \(...\) so that the content can be referred as \1 later
  • inner \(...\)* any number of matches of ...
  • [^()] any character that is not ( or )
  • \|\n or a line break to allow multi-line patterns
  • ) last character of the search pattern
  • /[\1] substitute by [ \1 = content form first \(...\) in the pattern ]
  • /g globally, so any number of substitutions per line

Notes

  • I hope I didn't get a typo now...
  • If the command is too long to be remembered, it might be mapped to a key.
  • If stored as a function, it might be called n times in one call to substitute nested parenthesis. To be honest, I don't know functions, someone might want to comment on that.
3
  • Your « notes » are exactly why I prefer tpope/surround—i didnt have to write the mapping, and i dont worry about typos. Functions arent so hard: the help is pretty extensive.
    – D. Ben Knoble
    Nov 13, 2019 at 12:55
  • Good point, I start learning it now :-)
    – Philipp
    Nov 14, 2019 at 9:16
  • This is a great answer, and does answer the OP question. Good breakdown too. Although as most people have started generally this sort of question is for a particular pair rather than all instances... But OP doesn't state that 🙂
    – 110100100
    Dec 4, 2020 at 19:58
0

Beside tpope/vim-surround, there is another good plugin called vim-sandwich that can add, replace and delete surround pairs of characters:

With vim-sandwich, you can use srb] or sr)] to replace a pair of () to []:

  • sr: start to replace sandwiched text
  • ) or b: the character pair you want to replace, (you use b when there is no ambiguity which pair you want to replace)
  • ]: the character pair you want to use
0

You only have to capture the inner part:

:s/\((.*)\)/[\1]/

I tried this and works on Python. If I do as @magikarp, the parenthesis does not disassapear. To fix it, you have to capture only the inner part.

Instead of

re.sub(r"(\(.*?\))",r"[\1]",x)

it has to be

re.sub(r"\((.*?)\)",r"[\1]",string)
-1

As @AndyB said, you can substitute with this:

:s/(\(.*\))/[\1]/

I would alter it slightly to this. I added a ? after the .* to make it non-greedy, which means it will try to find the shortest match, rather than the longest one.

:s/(\(.*?\))/[\1]/

You will also have issues if you have a right parenthesis inside a string. Which is a more complex problem to solve with regex.

2
  • 3
    Note, *? is not non-greedy for Vim, rather you need to use .\{-\} Oct 29, 2019 at 7:01
  • Oh, that's interesting, disregard my answer then.
    – Magikarp
    Oct 29, 2019 at 19:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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