naive231
naive231

Reputation: 1380

How do I substitute selected contents despite any regex characters in vim?

In following code:

int return_int_func() { return 0; }
float fv = return_int_func();

Obviously, compiler will warn me fv may lost precisions because of auto-casting. Face lots of those things, I want replace all stuffs with substitute command. In short, I want this:

float fv = static_cast<float>(return_int_func());

But real codes has lots of forms like that:

float fv = obj.int_field;
float fv = obj->load_int_field("name");
float fv = xx.yy->zz;

I want select my target (obj.int_field,obj->load_int_field("name") or xx.yy->zz) and replace it with static_cast<float>(\1). I tried this:

:'<,'>s/\%V/static_cast<float>(&)/g

But vim replaces all characters in selected word with static_cast... and that isn't what I want at all. Then I tried this:

:'<,'>s/\(\%V\)/static_cast<float>(\1)/g

Vim also do the same thing. I have no idea how to replace whole content (and despite any regex characters) with my pattern. Any suggestions?

Upvotes: 1

Views: 172

Answers (5)

glts
glts

Reputation: 22684

The solution is almost too easy! Here it is.

:s/\%V.*\%V./static_cast<float>(&)/

This is actually almost the same as the example from the :help. We can take away from this that we should all just have looked up :h /\%V first thing in the morning ...

\%V is a zero-width atom that matches stuff that is selected in Visual mode. Here it can match at the start of the Visual area. .* then matches (greedily) as much as it can; its greediness is reined in by the final \%V., which requires the last character of the match also to lie within the Visual area.


Tip: If you need to make this change many times over many lines, define the following mappings (even better: put them in your vimrc permanently).

nnoremap & :&&<CR>
xnoremap & :&&<CR>

Then you can repeat the substitution shown above by simply selecting something, and then pressing & to perform the substitution.

Upvotes: 1

glts
glts

Reputation: 22684

Let me try to paraphrase your question: You would like to Visual select some text, and then perform a substitution, where the selected text is also part of the replacement text.

I think in this case a macro is a much better tool.

To create the macro, first select the first piece of text that you want to wrap in the static cast. For example, select return_int_func(). (For each step, I'll show what the buffer looks like.)

  1. When you're ready, press qq to start recording into register q, then press c.

    float fv = |;
    
  2. Type the left part of your wrapper text, static_cast<float>(.

    float fv = static_cast<float>(|;
    
  3. Press CTRL-R " (Control-R followed by "): this will reinsert the original text.

    float fv = static_cast<float>(return_int_func()|;
    
  4. Type ) to complete the change, and then Escape to leave insert mode.

    float fv = static_cast<float>(return_int_func()▉;
    
  5. Finally, press q to stop recording.

At this point you have made the first change and also recorded it as a macro in register q.

For all remaining changes, simply select a target such as obj->load_int_field("name") and press @q to repeat the change.

Look up :help 10.1 for more information about macros.

Upvotes: 1

Kent
Kent

Reputation: 195029

if I understood you right, you want to do text substitution only on selected text. This is not so easy to do, at least no so easy as a :s command can do. Because, your visual selection can be in single line, can cross multi lines, also it could char-wise, line-wise, block-wise..

but it can be done with this function:

function! SubVisualText(pat, repl,flag)
    try
        let v_save = @v
        normal! gv"vy
        let s = @v
        let s = substitute(s, a:pat, a:repl,a:flag) 
        call setreg('v',s,visualmode())
        normal! gv"vp
    finally
        let @v = v_save
    endtry
endfunction 

you use it by:

  • source the function
  • visual select the area (could be done by v, V or Ctrl-V)
  • :<ctrl-u>call SubVisualText(pattern, replacement, flag)<Enter>

the <ctrl-u> is for removing the leading range, since the function doesn't need the range.

when you run it, it looks like:(I just tested with Ctrl-V selection)

enter image description here

Upvotes: 0

DJ.
DJ.

Reputation: 6774

You can try

:%s/float fv =(.*)$/float fv = static_cast<float>(\1)/g

Upvotes: 0

Jay
Jay

Reputation: 57899

The \%V facility is really not for acting on the selected text as a whole; more for searching inside of that text.

Assuming that you are going to be putting this into a function or maybe mapping this to a key combination, here is an alternative approach that does what you are looking for:

:exec 'normal! gv"adistatic_cast<float>('|exec 'normal! "apa)' 

Note that this will use your a buffer, so if you want to use another buffer you can change the two instances of "a with "x, where x is the buffer you wish to use.

Basically this is going to programmatically yank the selected text, insert static_cast<float>(, paste the text that was selected, and then insert ).

Upvotes: 0

Related Questions