When I use the command :%s/or/and/g to replace 'or' with 'and', Vim is altering the word color, i.e. (col(or)) to make it col(and), meaning, its changing the word color to coland and I don't need Vim to do this.
In such a scenario, which command should I use to alter 'or' to an 'and' and let the string 'color' be untouched?
Many thanks.
or matches the two characters no matter where they are so it will match or in or, for, normal, color, etc.
If you only want to match the word or, then you need to wrap your pattern in "word boundaries":
:%s/\<or\>/and/g
Which tells Vim that or should begin and end a "word" as defined by :help 'iskeyword'.
See :help \< and :help \>.
Related
I have a bunch of t_ prefixed fonction names in a header file and i would like to remove this prefix from some of them.
I have ended by typing :
:s/\(\s+\)t_\([^(]+\)(/\1\2(/c
But vim complains with Pattern not found
What is wrong in my pattern ?
You forgot to put a backslash before + to give it its quantifier meaning. You can also probably simplify it using \< to match the start of a word instead of capturing spaces.
I suggest breaking the problem down, first the search:
/\v\s+\zst_\ze.*\(
Now the substitution:
:s///\c
We can reuse a search pattern simply typing an empty search on the substitution
OBS: I suppose your functions have () at the end of the line, so .*().
Another thing; \zs and \ze to match only t_, for more see: :h \zs.
If you are using neovim you can see what happens befor hitting enter, just put these lines on your init.vim:
if has("nvim")
set inccommand=nosplit
endif
Is there a way to define what vim should recognize as a word? I want to assign \w+ regex to all word key motions such as "w", "e", "b"... I can do it for normal mode like this:
nnoremap <silent> w :call search('\w\+')<CR>
but it doesn't work for visual mode and operator-pending modes. It would be great if there is a setting to do this.
From what I understand from your question, and the discussion on Kaz' answer, I think what you're looking for is Kana's smartword plugin: http://www.vim.org/scripts/script.php?script_id=2470.
You're going to have to check the documentation with :help smartword, but the short version is, if you install the plugin and map the built-in word mappings to the plugin ones...
map w <Plug>(smartword-w)
map b <Plug>(smartword-b)
map e <Plug>(smartword-e)
map ge <Plug>(smartword-ge)
... then the built-ins will skip any non-word characters along the way. I've been using this for many, many years, and I'm quite happy with the way it behaves.
For the lower-case motions like w and e, the definition of a "word" is controlled by the :iskeyword option; see the :help iskeyword on that. Basically it consists of a list of characters given as individual characters or ranges, separated by commas. I think that various syntax files tweak this for different languages, so that these commands move by identifiers. It doesn't look like you can specify a regular expression for this.
The upper-case motions like W and E don't look like they can be reprogrammed. Their definition of a "WORD" is nonblank characters separated by whitespace, plus that each empty line counts as a "WORD".
However, unfortunately, it looks like there is a behavior in effect whereby the iskeyword characters simply separate the input into sequences of iskeyword characters, non-iskeyword characters and whitespace. When the w and related commands are used, they skip whitespace, but visit both the iskeyword tokens and the non-iskeyword tokens.
Remapping using :map to just a / or ? keystroke sequence works in both visual and command mode:
:map w /\<\w/^M
:map b ?\</\w^M
:map e /\w\>^M
It works in both because the / and ? searches work in both modes. Of course, it's an ugly solution because it clobbers the current search pattern and if you have :set hls (highlightsearch) on, the tips/tails of the words highlight.
The above searches are not very satisfactory because of the way the anchoring operators are behaving. For instance, I can't get them to "land" on the a in something like {abc or (abc.
The following mappings work a better. Each triggers several searches. The /. and ?. searches are used as a trick to go to the
next or previous character, such that if we are on the last character of a line, we go to the first one on the next line and vice versa.
:map b ?\w^M?\W^M/.^M
:map w /\W^M/\w^M
:map e /\w^M/\W^M?.^M
There are still some quirks. For instance, a list of words like:
abc
def
ghi
contains no match for the non-word class \W. The matching has to include line endings. Moving forward, an improvement to the w one in this regard is to add a match for the line ending like this:
:map w /\(\W\\|$\)^M/\w^M
Note the double backslash before the pipe! The rightmost backslash escapes the pipe so the processing of the :map command doesn't treat it as a command delimiter. Then we are left with \| which is the regex operator for branching. In a similar vein, the other two mappings can be improved; I'm leaving that as an exercise.
I want to add "caps" at the end of all words ending with "w".
For example "jaw" should become "jawcaps", and "blow" should become "blowcaps"
The following command is using regular expression for achieving upper requirement.
:%s/[A-Za-z][A-Za-z]*w[^A-Za-z]/&caps
But when I use the command above "jaw" converts into "jaw caps" not "jawcaps"
How can I remove the space which is located between "jaw" and "caps"?
How about this:
:%s/w\>\zs/caps/g
You have a problem in your regex, your regex would match a non character after the value w. In your case, match jaw[one space] instead of jaw
:%s/[A-Za-z][A-Za-z]*w[^A-Za-z]/&caps
^^^ here match a space
I suggest you to use a capture regex.
:%s/\([A-Za-z][A-Za-z]*w\)\([^A-Za-z]\)/\1caps\2
A better solution should be using look behind.
:%s/\w\w*w\w\#!/&caps
Sato Katsura's answer :%s/w\>\zs/caps/g works like this:
Search for every place where a "w" character is the last character of a word: /w\>.
But don't match that "w": only a zero-width space after the "w" should be matched: /w\>\zs (or /w\zs\>).
Replace that match with the word "caps": s/w\>\zs/caps/.
Do so on every line: range is %, and on every occurrence on those lines: flag is g.
Putting it together: :%s/w\>\zs/caps/g.
match word end :h /\>
set match start :h \zs
substitution command :h :s
range specification :h :range
substitution flags :h :s_flags
Here is the raw material I’m working with:
line1=a1 abc
line2=abc
line3=aba
line4=cbc
i want to match lines which do not contain character string of "abc" ,the result is :
line3=aba
line4=cbc
how can i get it in vim? maybe the expression is something such as (?!abc) in perl ,i am not sure how to write the regular expression in vim.
To match lines not ending with abc you could write the expression in two ways. My preferred is With very magic
/\v.*(abc)#!/
And with no very magic:
/.*\(abc\)\#!/
I recommend you to take some time to read:
:help magic
From Power Of G:
Delete all lines that do not match a pattern.
:g!/<pattern>/d
Of course, you can replace the d at the end to do something other than deleting the line...
It seems you're familiar with Perl regular expressions. You will probably be interested in :help perl-patterns where you can Vim equivalents for common Perl regex patterns. There, you can see that for a zero-width negative look-ahead, you want \#!.
For other zero-width patterns, including some not listed at :help perl-patterns, see :help /\#= and following. Also useful are \zs and \ze which can avoid some more complex zero-width matches in many cases.
Is there an easy way using a macro or ~10 line function (no plugin!) to center some text between the first and last word (=sequence of non-blank characters) on a line? E.g. to turn
>>> No user serviceable parts below. <<<
into
>>> No user serviceable parts below. <<<
by balancing the spaces +/-1? You can assume no tabs and the result should not contain tabs, but note that the first word may not start in column 1. (EDIT: ... in fact, both delimiter words as well as the start and end of the text to center may be on arbitrary columns.)
source this function:
fun! CenterInSpaces()
let l = getline('.')
let lre = '\v^\s*\S+\zs\s*\ze'
let rre = '\v\zs\s*\ze\S+\s*$'
let sp = matchstr(l,lre)
let sp = sp.matchstr(l,rre)
let ln = len(sp)
let l = substitute(l,lre,sp[:ln/2-1],'')
let l = substitute(l,rre,sp[ln/2:],'')
call setline('.',l)
endf
note
this function might NOT work in all cases. I just wrote it quick for usual case. this is not a plugin after all
the codes lines could be reduced by combining function calls. but i think it is clear in this way, so I just leave it like this.
if it worked for you, you could create a map
it works like this: (last two lines I typed #: to repeat cmd call)
You can use the :s command with the \= aka sub-replace-expression.
:s#\v^\s*\S+\zs(\s+)(.{-})(\s+)\ze\S+\s*$#\=substitute(submatch(1).submatch(3),'\v^(\s*)(\1\s=)$','\1'.escape(submatch(2),'~&\').'\2','')#
Overview
Capture the text (including white-space) between the >>> and <<< marks. Divide up the white-space on both sides of the text in half and substitute in the non-white-space text in between. This white-space balancing act is done via the regex engine's backtracking because math is hard. Lets go shopping!
Notes:
using \v or very magic mode to reduce escaping as this command is long enough
already
use # as an alternative separator instead of the usual / for :s/pat/sub/ in hopes to make it slightly more readable
Matching Pattern
:s#\v^\s*\S+\zs(\s+)(.{-})(\s+)\ze\S+\s*$#...
:s with no range supplied only do the substitution on the current line.
^\s*\S+ match the starting white-space followed by non-white-space. >>> in this case.
(\s+)(.{-})(\s+) match white-space followed by the "text" followed by white-space
3 capture groups: 1) leading white-space, 2) the "text", and 3) trailing white-space. These will be later referenced by submatch(1), submatch(2), and submatch(3) respectively
.{-} is vim-speak for non-greedy matching or .*? in perl-speak
without the non-greedy matching the second capture group would include too much white-space at its end
\S+\s*$ match the non-white-space (i.e. <<<) and any trailing white-space
Use \zs and ze to designate the start and end of the match to be replaced
Replacement
\=substitute(submatch(1).submatch(3),'\v^(\s*)(\1\s=)$','\1'.escape(submatch(2),'~&\').'\2','')
\= tells vim that replacement will be a vim expression. Also allows the use of submatch() functions
substitute({str}, {pat}, {sub}, {flags}) Our expression will be a nested substitution
substitute(submatch(1).submatch(3), ...) do a substitute over the concatenation of leading and trailing white-spacing captured in submatch(1) and submatch(3)
The {pat} is ^(\s*)(\1\s=)$. Match some white-space followed by white-space of the same length as the first or 1 character longer. Capture both halves.
escape(submatch(2),'~&\') escape submatch(2) for any special characters. e.g. ~,&,\1, ...
The {sub} is '\1'.escape(submatch(2),'~&\').'\2'. Replace with the the escaped submatch(2) (i.e. the "text" we want to center) in between the halves of white-space, \1 and \2 from the {pat}
No {flag}'s are needed so ''
Usage
If you use this often I would suggest creating a command and putting it in ~/.vimrc.
command! -range -bar -nargs=0 CenterBetween <line1>,<line2>s#\v^\s*\S+\zs(\s+)(.{-})(\s+)\ze\S+\s*$#\=substitute(submatch(1).submatch(3),'\v^(\s*)(\1\s=)$','\1'.submatch(2).'\2','')#`
Otherwise use this once and then repeat the last substitution via & on each needed line.
For more help see
:h :s/
:h :s/\=
:h sub-replace-\=
:h submatch(
:h substitute(
:h escape(
:h /\v
:h /\S
:h /\{-
:h /\zs
:h &
EDIT by Kent
Don't be jealous, your answer has it too. ^_^
I didn't change the command, just cp/paste to my vim. only add |noh at the end to disable highlighting.
If execute this command, it looks like:
I don't know of any good way. I usually do it in a semi-automatic way, by using :center on a line of text that only contains the parts that are to be centered and then move the result into the line containing the surrounding parts.
If nobody else has a better answer, perhaps boxes can help if you need to do this kind of thing a lot.