19

I need to search for lines which contain some word but do not contain a second word.

For example, find lines that contain the word "This" but not the word "red"

so that for a file containing these lines

This is a blue coat This is a red coat This is a purple coat That is a coat 

The search would locate the first and third lines only.

Thanks for any advice!

1
  • You can use the LogiPat plugin that is distributed with newer Vims Commented Sep 29, 2015 at 6:02

3 Answers 3

10

And there is also another way with :global command, as follows:

:g/This\C/v/red/p 

and the first :g command filter the lines contains This, and then passed into the second :v command to show lines that don't contain red, and at last, p (short for print) is applied to those lines with matches.

This is the charm of vim.

7
  • Thanks @TroyDaniel, could you explain what the \C does please? Commented May 17, 2020 at 16:07
  • In vim, the \C in regex means case-sensitive, and \c (with lower c) means case-insensitive. For more details, you can :h \C. Commented May 17, 2020 at 17:35
  • Thanks @TroyDaniel, I've been wanting to know how to do case-insensitive searches for decades! But your suggestion includes red, rather than excluding it, thus returning just the second line. Could you modify your answer please to exclude red? I tried playing around with the @ syntax above but couldn't get it to work in your setting Commented May 17, 2020 at 18:04
  • As long as you know :g command, you shold know :g! or :v command. If not, please do :h :v. Commented May 18, 2020 at 13:47
  • 4
    Note: this needs at least Vim 8.0.630. Using :g recursively was disallowed in older versions Commented May 19, 2020 at 8:14
30

You can use this command to print lines containing This and not red:

:g/\(.*This\)\&\(.*red\)\@! 
  • \& separates the branches like a logical AND because we want the lines that satisfy the two conditions (branches),
  • \(.*This\) is the first branch, it could simply be This but it is more generic that way,
  • \(.*red\)\@! is the second branch, \@! means "zero width match if the preceding atom doesn't match", like a logical NOT.

In other words:

\(.*This\) \& \(.*red\)\@! °°°°°°°°°° °° °°°°°°°°°°°° 'This' AND NOT 'red' 
1
  • 2
    Much thanks, this is very much like a query through formatted text. I was able to use this to find functions missing docstrings. Commented Jul 23, 2018 at 17:14
3

Take a look at this post.

Combine it with @romainl answer and you can do whatever you want.

Example: Let's say I want to add a const to the functions which doesn't have them.

 handleChange = value => { 

VIM script:

%s/\([ ]*\)\(\w* = .*$\)\&^\(\&\(.*const.*\)\@!.\)*$/\1const \2/gc 

Output:

 const handleChange = value => { 

Explanation:

\([ ]*\)\(\w* = .*$\) 

- get me all lines which has word =

\& 

- combine rules

^\(\&\(.*const.*\)\@!.\)*$ 

- the line shouldn't contain const.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.