Case preserving substitute in Vim
VimReplaceVim Problem Overview
Can this can be done in Vim?
> What I mean is: searching for 'BadJob'
> and replacing with 'GoodJob' would do
> the following replacements
>
> 'badjob' -> 'goodjob'
> 'BadJob' -> 'GoodJob'
> 'badJob' -> 'goodJob'
> 'BADJOB' -> 'GOODJOB'
Vim Solutions
Solution 1 - Vim
Use abolish.vim:
:%S/badjob/goodjob/g
Solution 2 - Vim
I don't know if this is the kind of solution you're looking for... but i've used this: keepcase.vim
There's no support otherwise in vim...
Solution 3 - Vim
sure u can
:s/\cbad/\= strpart(submatch(0), 0 ,1) == toupper(strpart(submatch(0), 0, 1)) ? "GOOD" : "good"/
ps. i'm guessing keepcase.vim encapsulates some similar logic :)
Solution 4 - Vim
For most (non-complex) cases, i recommend @rampion’s answer over mine.
If you got a minute, my post might be still be worthwhile, though. Level up your awareness for scripting gotchas.
You can just paste and adapt this:
(Of course, if you do this from time to time, you will want a plugin instead of this monstrosity. But for some who are in a hurry and only need it once, this is a quick hack for your pasting pleasure:)
:%s/\cbad\zejob/= ( submatch(0)[0] is# toupper(submatch(0)[0]) ? 'G' : 'g' ) . ( submatch(0)[1] is# toupper(submatch(0)[1]) ? 'OOD' : 'ood' )
Apart from the search pattern, you have to edit the four '
strings'
in the replacement code: Edit the parts in bold:
> :%s/\cbad\zejob/=
( submatch(0)[0] is# toupper(submatch(0)[0]) ? 'G' : 'g' ) .
( submatch(0)[1] is# toupper(submatch(0)[1]) ? 'OOD' : 'ood' )
Don't use this 'orange' version for pasting, since its linebreak characters will also break the command.
/\ze
is vim regex syntactic sugar for marking a positive lookahead: The pattern after \ze
is checked for, but not substituted.
is#
?? Let me explain… (If interested.)
#
(also in ==#
and others) enforces case sensitivity. Otherwise, with :set ignorecase
(which I use, because that is required for the useful :set smartcase
), vim will consider 'a' == 'A'
!!
http://i.stack.imgur.com/99eI5.jpg" height="140"> http://i.stack.imgur.com/UE9qp.jpg" height="140"> http://i.stack.imgur.com/Zeij0.jpg" height="140">
Crazy as it is, we really should account for it: Because it is user-settings-dependent, ==
should NEVAR be used! (Except where that would actually be what you want.) I will even follow the recommendation to use ==#
when comparing integers: http://learnvimscriptthehardway.stevelosh.com/chapters/22.html#code-defensively
is#
instead of ==#
is another way of coding defensively: It improves type safety: http://google.github.io/styleguide/vimscriptguide.xml?showone=Type_checking#Type_checking
It should be used when comparing against a string literal.
'single-quoted'
instead of "double quoted"
strings are another good practice: http://google.github.io/styleguide/vimscriptguide.xml?showone=Strings#Strings
HT @fc. - this answer builds on their answer, fixing a few shortcomings.
Solution 5 - Vim
If you're only matching an exact (case-independent) string with a few possible capitalizations, another possibility is:
:s/abc/\={'abc':'xyz','Abc':'Xyz'}[submatch(0)]/i
Solution 6 - Vim
An alternative to the keepcase plugin is SmartCase - replacing words while keeping original case. (Don't let yourself be discourage by the bad ratings.)
Solution 7 - Vim
What about
:%s/\Cbadjob/goodjob/
:%s/\CBadJob/GoodJob/
:%s/\CbadJob/goodJob/
:%s/\CBADJOB/GOODJOB/