7

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.

9

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 "]".

  • 2
    Welcome to this site AndyB! And great answer! – statox Oct 28 at 9:05
  • 1
    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. – Michael Anderson Oct 29 at 1:37
  • 1
    greedy .* should be change to non-greedy .\{-} – Maxim Kim Oct 29 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 at 7:53
15

With tpope/vim-surround, this is a simple

cs)]

away.

  • cs is the "change-surrounding" operator
  • ) is the "target"
  • ] is the replacement
  • 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 at 15:56
7

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.

2

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.

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.
  • 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 at 12:55
  • Good point, I start learning it now :-) – Philipp Nov 14 at 9:16
-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.

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

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.