[TriLUG] Negative search in Vi

Michael Tharp gxti at partiallystapled.com
Sat Apr 12 19:09:16 EDT 2008


Craig Taylor wrote:
> Negate your regular expression search, eg: for lines that don't have 'dog'
> use :
> 
> /^.*[^d][^o][^g].*$
> 
> disclaimer: this has not been tested - I believe it should work 'tho)
> 
> - Craig Taylor

 >>> foo = re.compile('^.*([^d][^o][^g]).*$')
 >>> sample = 'the quick brown fox jumped over the lazy dog'
 >>> bool(foo.search(sample))
True
 >>> foo.search(sample).groups()
(' do',)

The problem here is this:
1. The first ".*" gobbles up everything up to "dog"
2. [^d][^o][^g] doesn't match "dog", so it backtracks by one character 
to " do"
3. It matches, since " do" != "dog"
4. The second ".*" gobbles up the remainder of the string

Doing negative matches is surprisingly difficult and I honestly can't 
say I know of a way to do this with just a regular expression, either. 
Aaron's suggestion of deleting all matching lines and stepping through 
the remainder is probably the most plausible. Honestly, if this is 
possible, it has to be a feature of vim itself, not some regex trickery.

As I wrote this, Kevin posted a recommendation for lookahead/behind 
assertions, but remember that those only work if you have something to 
anchor them to! You can't say "match anything but dog" with an assertion 
unless you have something that you *do* match first, and then say "match 
if it is not followed by dog". In Kevin's example, the anchor is the end 
of the string, but this is insufficient for simply checking whether 
something is not present if it could be anywhere in the middle.

-- m. tharp



More information about the TriLUG mailing list