Replace while keeping certain “words” in vi/vim

2019-02-05 03:47发布

问题:

For example, if I have $asd['word_123'] and I wanted to replace it with $this->line('word_123'), keeping the 'word_123'. How could I do that?

By using this:

%s/asd\[\'.*\'\]/this->line('.*')/g

I will not be able to keep the wording in between. Please enlighten me.

回答1:

Using regex, you could do something like :%s/\$asd\['\([^']*\)'\]/$this->line('\1')/g

Step by step:

%s - substitute on the whole file

\$asd\[' - match "$asd['". Notice the $ and [ need to be escaped since these have special meaning in regex.

\([^']*\) - the \( \) can be used to select what's called an "atom" so that you can use it in the replacement. The [^'] means anything that is not a ', and * means match 0 or more of them.

'\] - finishes our match.

$this->line('\1') - replaces with what we want, and \1 replaces with our matched atom from before.

g - do this for multiple matches on each line.

Alternative (macro)

Instead of regex you could also use a macro. For example,

qq/\$asd<Enter>ct'$this->line(<Esc>f]r)q

then @q as many times as you need. You can also @@ after you've used @q once, or you can 80@q if you want to use it 80 times.

Alternative (:norm)

In some cases, using :norm may be the best option. For example, if you have a short block of code and you're matching a unique character or position. If you know that "$" only appears in "$asd" for a particular block of code you could visually select it and

:norm $T$ct'this->line(<C-v><Esc>f]r)<Enter>

For a discourse on using :norm more effectively, read :help :norm and this reddit post.



回答2:

Try using

:%s/\$asd\[\'\([^\']\+\)\'\]/$this->line('\1')/g