1

I've the following content:

a1a foo bar buzz
foo b2b bar buzz
foo bar c3c buzz
foo bar buzz d4d

where I can match all words consisting only alpha characters by the following pattern:

/\<[a-zA-Z]*\>

Now, how can I remove all words which doesn't match the pattern?

So the final content is:

foo bar buzz
foo bar buzz
foo bar buzz
foo bar buzz

I've checked Search for lines not containing pattern page, but without luck.

To remove some words patching the pattern, global command can be used:

:g/\<[a-zA-Z]*\>/;&

as per this post.

However when doing opposite:

:v/\<[a-zA-Z]*\>/;&

there is this message:

Pattern found in every line

1
  • In this case, you could simply search for \a\d\a and remove that. But that doesn't answer the general question of How to remove something that doesn't match a search
    – DJMcMayhem
    Commented Oct 5, 2017 at 17:10

1 Answer 1

3

You can do this with \@<! (which is sometimes called "negative lookbehind"):

/\<\w\+\>\(\<\a\+\>\)\@<!

    \@<! Matches with zero width if the preceding atom does NOT match just
         before what follows.

It is a bit tricky to understand at first:

  1. Initially we try searching for all words (including ones with numbers) /\<\w\+\>.
  2. Since we want some words to match and not others, we use a "zero-width" in this position to force certain text to match. In this case, the text we want is words without a digit: \<\a\+\>.
  3. We wrap the second pattern in \(...\)\@<!, which denotes the zero-width mentioned above. We use \(...\) to create a single atom.

Now, to remove those words, we can use :substitute, but add \s\? to take care of the spaces.

:%s/\<\w\+\>\(\<\a\+\>\)\@<!\s\?//g

We can make this slightly shorter using \v very magic:

:%s/\v<\w+>(<\a+>)@<!\s?//g

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.