I've also missed this feature several times.
It is mentioned in the todo list:
:h todo
- ":s/pat/foo/3": find 3rd match of "pat", like sed. (Thomas Koehler)
8 Add an argument after ":s/pat/str/" for a range of matches. For example,
":s/pat/str/#3-4" to replace only the third and fourth "pat" in a line.
- Add number option to ":s//2": replace second occurrence of string? Or:
:s///N substitutes N times.
--
Andy
Vim substitute is no more identical to sed, than Vim regexps are identical to
perl regexps. They may be similar, but Vim doesn't try to behave identically
as any other program (except Vi when in 'compatible' mode, and even then there
are documented differences). To learn how ":s" works in Vim, you should read
":help :s" and what it resends to, not "man sed". In particular, the syntax of
the ":s" command is defined as
:[range]s[ubstitute]/{pattern}/{string}/[flags] [count]
Under ":help :s_flags", no numeric flags are mentioned. I suppose your 3 is
understood as a count, i.e., replace in three lines, as mentioned under ":help
:s". The expression "replace in three lines" might be ambiguous; it may depend
on the presence or absence of the "g" flag. Without it, only the first
occurrence on its line is replaced. To replace the 3rd occurrence on all
lines, you could for instance use (untested)
:1,$s/^[^c]*c[^c]*c[^c]*\zsc/char
Use a different range to act on only part of the file.
Best regards,
Tony.
--
hundred-and-one symptoms of being an internet addict:
234. You started college as a chemistry major, and walk out four years
later as an Internet provider.
:call feedkeys('nnyq') | s/c/char/gc
What's the problem ? ;-)
Putting in it in a command :
com! -nargs=1 -range SedS <line1>,<line2>call SedS(<q-args>)
"%SedS/b/a/2
func! SedS( s_expr ) range
if a:s_expr !~ '\d\+$'
exec a:firstline.','.a:lastline.'s'.a:s_expr
else
let nth = matchstr(a:s_expr,'\d\+$')+0
let fk_expr = repeat('n',nth-1)."yq"
let s_expr = strpart(a:s_expr,0,strlen(a:s_expr)-strlen(nth))
for line in range(a:firstline,a:lastline)
exe 'call feedkeys("'.fk_expr.'") | '.line.'s'. s_expr .'gce'
call inputsave()
endfor
endif
endfun
Note: That's just a proof of concept, don't ask me where all the saved
keystrokes endup ( inputsave() ).
-ap
--
Ich hab geträumt, der Krieg wär vorbei.
Nice idea. For the few occasions where this is needed, it's a really cool
workaround. Here with some improvements:
- added :sil-ence
- uses input() instead of inputsave() -- no risk of mem overflow
- prints the number of changes, like the original :s would do
- untested: the surrounding inputsave()/inputrestore() pair will be needed
when used within a mapping
com! -nargs=1 -range SedS <line1>,<line2>call SedS(<q-args>)
"%SedS/b/a/2
func! SedS( s_expr ) range
if a:s_expr !~ '\d\+$'
exec a:firstline.','.a:lastline.'s'.a:s_expr
return
endif
call inputsave()
let nth = matchstr(a:s_expr,'\d\+$')+0
let fk_expr = repeat('n',nth-1)."yq\r"
let s_expr = strpart(a:s_expr,0,strlen(a:s_expr)-strlen(nth))
let nchanges = 0
for line in range(a:firstline,a:lastline)
exe 'call feedkeys("'.fk_expr.'") | sil' line.'s'. s_expr .'gce'
sil let nchanges += input("") !~ "y"
endfor
if nchanges > &report
echo nchanges "substitutions on" nchanges "lines"
endif
call inputrestore()
endfunc
--
Andy
>A.Politz schrieb:
>
>
>>anokun7 wrote:
>>
>>
>>
>>>In sed, you could do: s/c/char/3
>>>
>>>
>>>
>>:call feedkeys('nnyq') | s/c/char/gc
>>
>>What's the problem ? ;-)
>>
>>
>>
>>
>
>Nice idea. For the few occasions where this is needed, it's a really cool
>workaround. Here with some improvements:
>
>- added :sil-ence
>- uses input() instead of inputsave() -- no risk of mem overflow
>- prints the number of changes, like the original :s would do
>- untested: the surrounding inputsave()/inputrestore() pair will be needed
> when used within a mapping
>
>
- avoid redraws per lazyredraw
com! -nargs=1 -range SedS <line1>,<line2>call SedS(<q-args>)
fun! SedS( s_expr ) range
if a:s_expr !~ '\d\+$'
exec a:firstline.','.a:lastline.'s'.a:s_expr
return
endif
let lz_save = &lz
set lz
call inputsave()
let nth = matchstr(a:s_expr,'\d\+$')+0
let fk_expr = repeat('n',nth-1)."yq\r"
let s_expr = strpart(a:s_expr,0,strlen(a:s_expr)-strlen(nth))
let nchanges = 0
for line in range(a:firstline,a:lastline)
exe 'call feedkeys("'.fk_expr.'") | sil' line.'s'. s_expr .'gce'
sil let nchanges += input("") !~ "y"
endfor
if nchanges > &report
echo nchanges "substitutions on" nchanges "lines"
endif
call inputrestore()
let &lz = lz_save
endfun
On Sun, 13 Jan 2008, anokun7 wrote:
> What I am trying to do is to replace the nth occurrence of a
> character with something else.
>
> In sed, you could do: s/c/char/3
>
> So in a set of lines like this
>
> abc abc abcd
> c c c c
> abcd abc
>
> it would become - after substitution:
>
> abc abc abchard
> c c char c
> abcd abc
>
> Seems like it doesnt work - when I do that in VIM, I get the first
> occurence in the 3rd line replaced to become:
>
> abc abc abcd
> c c c c
> abchard abc
>
> Am I doing something wrong or is VIM not like sed at all?
Why don't you filter your lines through sed?
regards,
Christian
--
:wq!