2

I have several lines, and each line has 2 quoted string, and I want to replace all space with "_" for the first quoted string.

How to do that? Could I use macro?

select 'a b c','a b c' union all
select 'a e1 c d','a e1 c d' union all
select 'a f11 c','a f11 c' union all
select 'a g1 c','a g1 c' union

result:

select 'a_b_c','a b c' union all
select 'a_e1_c_d','a e1 c d' union all
select 'a_f11_c','a f11 c' union all
select 'a_g1_c','a g1 c' union

2 Answers 2

5

I think the macro is a good use here :

0vi':s/\%V /_/g^M

Decomposing the macro :

0        " go to the start of the line
vi'      " visually select inside '
:s/       " start a substitute command
\%V      " tell the substitute to operate over the last visual selection
 /_/g    " there is a ' ' here : replace every ' ' with a '_'
^M       " press <CR>

Reference for \%V : http://vim.wikia.com/wiki/Search_and_replace_in_a_visual_selection

You can then go line over line, or execute the macro over all lines at the same time (see https://stackoverflow.com/a/3338480/2558252)

3
  • 1
    Do you really need to leave visual mode first? I know there are cases when you do, but I think with \%V you'd be fine starting the substitute from visual mode. Save some keystrokes :)
    – jjaderberg
    Aug 21, 2015 at 10:26
  • 1
    0f'v; could be 0vi'
    – Kent
    Aug 21, 2015 at 11:14
  • I think there is an <Esc> missing after the vi', otherwise you have to manually delete the :'<,'>s/ and retype it. At least in vim 8.0.
    – naught101
    Jan 13, 2019 at 22:30
6

A macro like @Nobe4's may be the easiest, but you could also do a substitution. It can be tricky to express the substitution since you want it to be 'global' within the quoted string, but not really global for the line (i.e., replace all whitespace, but only for the first quoted string on the line). One way is to do a non-global substitution to replace the whole first quoted string, and for replacement use an expression which makes a global substitution on that string from ' ' to '_'.

:%s/'[^']*'/\=substitute(submatch(0), ' ', '_', 'g')/

or

:%s/'.\{-}'/\=substitute(submatch(0), ' ', '_', 'g')/

Maybe this feels a little clunky compared to a macro, but it can be a useful technique sometimes.

Details

  • : - enter cmdline mode
  • % - for all lines in buffer
  • s - substitute (the three / characters delimit the substitute command, see :help :substitute)
  • '.\{-}' or '[^']*' - regex that matches anything surrounded by single quotes
  • \= - substitute with an expression (see :help sub-replace-expression)
  • substitute() - the expression is a call to :help substitute()
  • submatch(0) - the entire matched string is retrieved with submatch(0) and is the first argument to substitute()
  • ' ', '_' - the substitution on the string
  • 'g' - global flag, i.e., substitute all occurrences

If we had ended the :substitute command with a global flag (/g) then it would have substituted all occurrences of quoted strings on the line. As it is, it only does the first. In the call to substitute() however we do use the global flag ('g') in order to replace all occurrences of ' ' in the quoted string.

2
  • I like your solution, can you give some more details for the differents parts ?
    – nobe4
    Aug 21, 2015 at 10:27
  • It's always good to see examples of advanced search replace usage like this to try to boost one's knowledge.
    – NeilG
    Sep 25 at 23:29

Your Answer

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

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