danbruegge
danbruegge

Reputation: 2243

VIM: Replace function call without the arguments

how can i search and replace a function call, but without the arguments of the function?

For short, i will search and replace from foobar(arg1, arg2) to foobar: arg1, arg2;

My goal is to keep the arg1, arg2.

How can i solve this? Is there a best practice?

Upvotes: 3

Views: 1030

Answers (4)

Amadan
Amadan

Reputation: 198556

Try this:

Insert a line at the top of the file - we'll write a macro here. (That's the letter O, not a zero.)

ggO

Instructions for searching for a string of word-characters followed by an open paren, and leave the cursor at the end of the match

/\w*(/e<Ctrl-V><Ctrl-M>

Then we'd go to the matching parenthesis and replace it with a semicolon

%r;

Jump back to the other parenthesis (ctrl-letter O again, not zero)

<Ctrl-V><Ctrl-O>

Replace this parenthesis with :

s:<Space><Ctrl-V><Esc>

Then execute this macro again (assuming it is in the q register)

@q

Our macro is done, exit insert mode (your line should read: /\w*(/e^M%r;^Os: ^[@q now)

<Esc>

Pull the line into the q register (which also removes it from the current file, returning your file to its previous pristine state)

"qdd

Finally, the Big Moment: execute the recursive macro we've built in the @q register, which will transform the whole file.

@q

BENEFITS: it handles nested functions correctly, since it is not relying on the regular expressions that have trouble capturing parenthesis matching. Instead we rely on the % command to match parentheses.

Demo:

foo(bar, baz)
foo(foo(bar), baz(), foo(foo, foo, foo))
foo(bar(baz()))

turns into

foo: bar, baz;
foo: foo: bar;, baz: ;, foo: foo, foo, foo;;
foo: bar: baz: ;;;

EDIT: typo (\w, not \e in search).

Upvotes: 2

Ingo Karkat
Ingo Karkat

Reputation: 172778

Here's one approach that works with arbitrarily named arguments:

:%s/\(\<foobar\)(\(.*\))/\1: \2;/g

Basically, it captures (via \(...\)) the function name and the arguments (without the parentheses), and then re-assembles it in a :substitute command. The \< asserts a keyword boundary, so that it doesn't match myfoobar(.

Caveats

Note that regular expressions are limited in their ability to parse programming language constructs; a proper refactoring tool allows more precise and safer modifications.

One problem in your example is how to deal with the arguments; I've chosen a greedy match (.*), but this would improperly handle a construct like foobar(arg1, arg2); baz(arg3, arg4). A non-greedy match (.\{-} in Vim), on the other hand, would fail to capture embedded sub-calls like foobar(hostname(), arg2). Writing a regular expression to handle all cases is close to impossible, so it's your responsibility to use this wisely (maybe by adding the c flag to the :substitute command and acknowledging each replacement manually).

Upvotes: 2

falsetru
falsetru

Reputation: 369464

Use following command:

:%s/\v(\w+)\(([^()]*)\)/\1: \2;/g

NOTE This does not work if there nested function call.

See a demo.

Upvotes: 3

KeyNone
KeyNone

Reputation: 9190

You may search for

(foobar)(\()(arg1, arg2)(\))

and replace it with

\1: \3;

(demo @ regex101)

So, in VIM it may be something like

:s/(foobar)(\()(arg1, arg2)(\))/\1: \3;/g

Upvotes: 1

Related Questions