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 Sep 29, 2015 at 6:02

3 Answers 3

9

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?
    – Leo Simon
    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. 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
    – Leo Simon
    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. May 18, 2020 at 13:47
  • 4
    Note: this needs at least Vim 8.0.630. Using :g recursively was disallowed in older versions 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.
    – user12827
    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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.