16

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!

  • You can use the LogiPat plugin that is distributed with newer Vims – Christian Brabandt Sep 29 '15 at 6:02
3

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.

| improve this answer | |
  • Thanks @TroyDaniel, could you explain what the \C does please? – Leo Simon May 17 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. – Troy Daniel May 17 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 at 18:04
  • As long as you know :g command, you shold know :g! or :v command. If not, please do :h :v. – Troy Daniel May 18 at 13:47
  • 1
    Note: this needs at least Vim 8.0.630. Using :g recursively was disallowed in older versions – Christian Brabandt May 19 at 8:14
26

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'
| improve this answer | |
  • Much thanks, this is very much like a query through formatted text. I was able to use this to find functions missing docstrings. – Joshua Detwiler Jul 23 '18 at 17:14
1

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.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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