VIM select all matching patterns in one line - vim

Can anybody please help on my issue regarding VIM?
This is my scenario:
The red redfox02animal jump over the blue reddog01animal.
I tried this search patten
/red.*[0-9]
but the result is "redfox02animal jump over the blue reddog01". What I want are two matched "redfox02" and "redfox01"
Any advice?

Use /red.\{-}[0-9]\+ instead of /red.*[0-9], the former is non-greedy, while the latter (default) is greedy.

this should go too:
/red\D*\d\+
Note that this gives the same matches as Tobi's answer, the first match is:
red redfox02
if you just want to have redfox02 and reddog01 (there is no redfox01 in your input, you cannot get it, as you stated in your question), you can try:
/red[^0-9 ]\d\+

Related

vim Search Replace should use replaced text in following searches

I have a data file (comma separated) that has a lot of NAs (It was generated by R). I opened the file in vim and tried to replace all the NA values to empty strings.
Here is a sample slimmed down version of a record in the file:
1,1,NA,NA,NA,NATIONAL,NA,1,NANA,1,AMERICANA,1
Once I am done with the search-replace, the intended output should be:
1,1,,,,NATIONAL,,1,NANA,1,AMERICANA,1
In other words, all the NAs should be replaced except the words NATIONAL, NANA and AMERICANA.
I used the following command in vim to do this:
1, $ s/\,NA\,/\,\,/g
But, it doesn't seem to work. Here is the output that I get:
1,1,,NA,,NATIONAL,,1,NANA,1,AMERICANA,1
As you can see, there is one ,NA, that is left out of the replacement process.
Does anyone have a good way to fix it? Thanks.
A trivial solution is to run the same command again and it will take care of the remaining ,NA,. However, it is not a feasible solution because my actual data file has 100s of columns and 500K+ rows each with a variable number of NAs.
, doesn't have a special meaning so you don't have to escape it:
:1,$s/,NA,/,,/g
Which doesn't solve your problem.
You can use % as a shorthand for 1,$:
:%s/,NA,/,,/g
Which doesn't solve your problem either.
The best way to match all those NA words to the exclusion of other words containing NA would be to use word boundaries:
:%s/,\<NA\>,/,,/g
Which still doesn't solve your problem.
Which makes those commas, that you used to restrict the match to NA and that are causing the error, useless:
:%s/\<NA\>//g
See :help :range and :help \<.
Use % instead of 1,$ (% means "the buffer" aka the whole file).
You don't need \,. , works fine.
Vim finds discrete, non-overlapping matches. so in ,NA,NA,NA, it only finds the first ,NA, and third ,NA, as the middle one doesn't have its own separate surrounding ,. We can modify the match to not include certain characters of our regex with \zs (start) and \ze (end). These modify our regex to find matches that are surrounded by other characters, but our matches don't actually include them, so we can match all the NA in ,NA,NA,NA,.
TL;DR: %s/,\zsNA\ze,//g

Is this change to Vim's syntax coloring file for sed good or disrupting?

Summary
I'm not asking your opinion about the proposed change being good, bad, amazing, or what.
I'm just asking your help to answer this question: does the change I propose for the syntax coloring of the comments break the syntax coloring of something else (keywords, strings, syntax errors, ...)?
The question above is not opinion based, as my change either does break something or it doesn't. That's it.
Original question
I have created the issue #5876 on Vim's GitHub page to propose a change to vim/runtime/syntax/sed.vim, but it has not received much attention, so I'm considering creating a PR for the change.
In fact, I created an issue instead of a PR because I'm not totally confident the change is not disruptive, hence this question.
The issue is with line 20:
syn match sedComment "^\s*#.*$"
because of which only "full line" comments are colored as comments. Using trailing comments following a command (allowed by GNU sed, for instance), stimulates some red background coloring (since it's considered an error by the syntax coloring logic, I guess).
I think it would be reasonable to relax this definition of comments to permit GNU sed-style comments, for the simple reason that the rule is less restrictive.
In this respect, I have noticed that changing that line to
syn match sedComment "\s*#.*$"
i.e. just removing the anchor ^, seems to be enough. I have also tried testing it by putting some # in search and replace strings in a sed script, and it seems fine.
However I don't feel confident with Vim syntax coloring files, so I would like to be sure that regex, as I edited it, is not causing false positives.
To demonstrate why I'm not confident about it, take this single-line sed script
s/aaa/bbb/#ccc
here # is not colored as a comment, and ccc's background is red (like an error?), whereas, just adding a space, give the correct coloring:
s/aaa/bbb/ #ccc
Therefore I think that my edit works (or seems to work) because of precedence rules between the several syntax coloring directives (with respect to this specific example with s/aaa/bbb/#ccc, I think that # just after the closing delimiter of the s command has a meaning in the language, but I don't know; the GNU Sed man page doesn't say anything about it).
Edit
Another example suggested in the comments is the following, the syntax coloring of which is not broken by the proposed change
s/#if !defined(\([^)]*)/#ifndef \1/ # with or without this comment is fine
My research
I have eventually found some time to study :h E410 and now I have an answer.
From there I read that
1. Keyword
[...] It will only match with a complete word [...]
2. Match
This is a match with a single regexp pattern.
3. Region
This starts at a match of the "start" regexp pattern and ends with a match with the
"end" regexp pattern. Any other text can appear in between. A "skip" regexp
pattern can be used to avoid matching the "end" pattern.
Since the line I'm going to change uses the syntax 2.,
point 1. is not relevant,
point 3. is relevant, as in general there can be an overlap between the what syn match and syn region match.
(By the way, I verified that syn region uses a lazy regex, probably \_.\{-} looking at some examples afterwards, to match stuff between the start and end regexp patterns.)
Then from :h :syn-priority
An item that starts in an earlier position has priority over items that start in later positions.
The answer
Therefore, changing
syn match sedComment "^\s*#.*$"
to
syn match sedComment "\s*#.*$"
should not introduce any syntax error, the reason being that if a text matching the above regex is not actually a comment (as is the case for e.g. the command s/#/hash/), then it must be preceded by some non-comment syntax which will be matched by other syn match/syn region groups. Since this match starts before where the group sedComment starts to match, the former has precedence on the latter.
In conclusion, unless something is broken with sed.vim already, the proposed change will not result in a wrong syntax coloring.
Further observations
Actually, there is already something wrong in sed.vim, and my proposed edit does not solve it (I should edit some other line in sed.vim to fix it, but I'm a bit lazy now).
For instance, in the following line, which is illegal because a is not a valid flag, a does not get the Error coloring.
s/x/y/a
My proposed edit does not solve this bug.
For the same reason, since some other syntax rule is eating 1 character after the third delimiter in the substitution command, the GNU-sed-valid comment in the following command is incorrectly colored
s/x/y/#hello
# │└───┴─── colored as Error
# └─ not colored
The coloring would be wrong even for an old version of sed which does not allow trailing comments, as the Error coloring should include the # too.
My proposed edit does not solve this bug either.
One more observation
The change I propose causes single-letter commands to be highlighted as Error if they are followed by a comment
p # this is a comment
│ └─────────────────┴─── colored as Comment (ok)
└────── colored as Error (bad)
This again, is not a worsening, as the current sed.vim colors almost the whole line above as an Error.

Vim - Find pattern on currently line ONLY

I'm wondering if there is a way to find a pattern, but restrict it to the current line. Basically, the equivalent of /PATTERN but restricted to the current line, rather than the entire document.
I've tried :s/PATTERN, but that deletes the pattern from the line and places my cursor at the beginning of the line, which is not at all what I need. I was hoping you could search without replacing...
I'm hoping to use this for a macro in order to place my cursor at the start of that pattern, as would happen when you do /PATTERN on the entire file, so anything that is macro-friendly is even better.
Any vim users out there that might have an idea?
EDIT: 0/PATTERN in a macro would work for my current need, but I'm hoping there's a more specific way to restrict the search.
ANSWER: There's a few ways posted in here so far, but the one I like best right now is using Shift+V to select the current line visually, followed by /\%V to search only in the visual selection. Then Shift+V again will turn off the visual mode.
My knowledge about macro is limited, but interactively, you can select current line with Shift + V, and then do /\%Vsearch (see http://vimdoc.sourceforge.net/htmldoc/pattern.html#/\%V).
try to Find first character of the Pattern by typing
f <letter>
It's not exactly what you need but can help to solve the problem.
/\%9lsearch
Where \%9 means line number 9.
Typing in the line number is still a bit lame. You can ctrl+r= followed by a vim expression and enter to evaluate the vim expression and insert its output. line('.') will return the line of the cursor.
In one complete step
/\%<c-r>=line('.')<cr>lsearch
For more help see:
:h /\%l
:h i_CTRL-R
Place the cursor on the line you want to search in
Select it with shift+v
Type / to begin searching
Prefix your term with \%V, e.g. \%Vabc to search for abc in only the visually selected blocks (in our case the single line)
You can search without replacing by using
:s/PATTERN//gc
Then press n to skip the replacement. If the pattern is not found, you won't even be asked.
You could also just highlight the current line or the range of lines.

Delete anything other than pattern

Let's say this is my text:
this is my text this
is my text this is my text
my text is this
I would like to highlight all text except pattern and delete the highlighted text.
p.e. text: this must be the result.
text
texttext
text
I've found the code how to select all text except pattern:
\%(\%(.{-}\)\#!text\zs\)*
however I don't know how to delete all highlighted text.
This doesn't work:
:%s/\%(\%(.{-}\)\#!bell\zs\)*//
Can anyone help me?
Try this:
:%s/\(^\|\(text\)\#<=\).\{-}\($\|text\)\#=//g
Explanation:
\(^\|\(text\)\#<=\) # means start of line, or some point preceded by “text”
.\{-} # as few characters as possible
\($\|text\)\#= # without globbing characters, checking that we reached either end of line or occurrence of “text”.
Another way to do it:
Create a function that count matches of a pattern in a string (see :help match() to help you design that)
Use: :%s/.*/\=repeat('text', matchcount('text', submatch(0)))
Forgive me, because I'm not a vim expert, but wouldn't prepending the search with v find the inverse so that you could do something like this?
:v/pattern/d
I've implemented Benoit's clever regular expression as a custom :DeleteExcept command in my PatternsOnText plugin. It offers other related commands like :SubstituteExcept or :SubstituteInSearch, too.
OP's example would be
:%DeleteExcept /text/
Comparing that with #Benoit's explicit command (:%s/\(^\|\(text\)\#<=\).\{-}\($\|text\)\#=//g), it's a lot simpler.

vim does not find and replace simple phrase that is clearly present

I have a simple vim problem that Google hasn't managed to help me with. Any thoughts are appreciated.
I do the following search and replace:
:s/numnodes/numnodes1/g
On a file containing the following text:
numprocs=0
numnodes=0
I get
E486: Pattern not found
The position of the green square which indicates where I'd start typing is clearly above the pattern. I tried searching for other short phrases not involving regex, which are also present, which also fail. A simple /numnodes highlights matches as expected. Does anyone have any idea what might be the matter with vim?
Try :%s/searchphrase/replacephase/g
Without the % symbol Vim only matches and replaces on the current line.
try using this:
:%s/numnodes/numnodes1/g

Resources