bhinks
bhinks

Reputation: 71

RegEx with Not Condition

I am trying to use a regular expression which performs the following action: match any text without the word "Chrome" followed by the word "Safari"

I put together a python script that isn't working.

#!/usr/bin/env python

import sys
import re

# any text but 'Chrome' followed by Safari

negative_re = re.compile( '(?<!Chrome).*?Safari' )

matcher = negative_re.search( sys.argv[1] )
if matcher:
  print "match"
else:
  print "no match"

I tried the following examples

test_negative.py "Chrome Mobile/12345 Safari"
> match

test_negative.py "Like MAC OS Safari"
> match

I was hoping for the first to return "no match" and the second to return "match". If anyone could help with the regular expression, that would be great, thanks.

Upvotes: 4

Views: 606

Answers (3)

kiriloff
kiriloff

Reputation: 26333

This is working

import sys
import re

# any text but 'Chrome' followed by Safari

negative_re = re.compile( '^(?!Chrome).*(Safari).*$' )

matcher = negative_re.search( "Void MAC OS Safari"  )
if matcher:
  print ("match")
else:
  print ("no match")

gives

>>> 
match

and

matcher = negative_re.search( "Chrome MAC OS Safari"  )
if matcher:
  print ("match")
else:
  print ("no match")

gives

>>> 
no match

Upvotes: 0

Ro Yo Mi
Ro Yo Mi

Reputation: 15000

Consider the following powershell example of regex. This regex satisfies your examples however it does use some lookarounds which might not be allowed by python.

  • (?<!Chrome.*?)Safari(?!.*?Chrome)|(?<!Safari.*?)Chrome(?!.*?Safari)|(?<!(Chrome|Safari).*?)$ demo'd here as Output 1. fails only if chrome or safari are on the same string

  • (?<!Chrome.*?)Safari|(?<!Safari.*?)$ demo'd here as Output 2. fails only if chrome is followed by safari

Example

$Matches = @()
[array]$input = @()

$input += 'Chrome Mobile/12345 Safari'
$input += 'Like MAC OS Safari'
$input += 'Safari Mobile/12345 Chrome'
$input += 'Like MAC OS chrome'
$input += 'Internet Explorer is deprecated'
$input += 'I like Chrome  better then Safari for looking at kittens'
$input += 'Safari is easier to vote with'


$Regex = '(?<!Chrome.*?)Safari(?!.*?Chrome)|(?<!Safari.*?)Chrome(?!.*?Safari)|(?<!(Chrome|Safari).*?)$'


Write-Host Output 1

foreach ($String in $Input) {
    if ( $String -imatch $Regex ) { 
        write "'$String' `t matched"
        } else {
        write "'$String' `t did not match"
        } # end if 
    } # next


Write-Host 
Write-Host Output 2


# but I want to allow for only:
#  match any text without the word "Chrome" followed by the word "Safari"
$Regex = '(?<!Chrome.*?)Safari|(?<!Safari.*?)$'


foreach ($String in $Input) {
    if ( $String -imatch $Regex ) { 
        write "'$String' `t matched"
        } else {
        write "'$String' `t did not match"
        } # end if 
    } # next

Yields

Output 1
'Chrome Mobile/12345 Safari'     did not match
'Like MAC OS Safari'     matched
'Safari Mobile/12345 Chrome'     did not match
'Like MAC OS chrome'     matched
'Internet Explorer is deprecated'    matched
'I like Chrome  better then Safari for looking at kittens'   did not match
'Safari is easier to vote with'      matched

Output 2
'Chrome Mobile/12345 Safari'     did not match
'Like MAC OS Safari'     matched
'Safari Mobile/12345 Chrome'     matched
'Like MAC OS chrome'     matched
'Internet Explorer is deprecated'    matched
'I like Chrome  better then Safari for looking at kittens'   did not match
'Safari is easier to vote with'      matched

Summary

  • Output one

    • (?<!Chrome.*?)Safari(?!.*?Chrome) looks for the word Safari which is not preceded or followed by Chrome
    • | or
    • (?<!Safari.*?)Chrome(?!.*?Safari) looks for the word chrome not preceded or followed by the word Safari
    • | or
    • (?<!(Chrome|Safari).*?)$ not anywhere on the line
  • Output two which satisfies the exact condition in the original question match any text without the word "Chrome" followed by the word "Safari"

    • (?<!Chrome.*?)Safari if Safari is exists and is not proceeded by Chrome
    • | or
    • (?<!Safari.*?)$ the term safari is not found in the string

Upvotes: 0

mgilson
mgilson

Reputation: 309881

Can't you just write the regex to match if Safari follows Chrome and then negate the conditional?

#!/usr/bin/env python

import sys
import re

# any text but 'Chrome' followed by Safari

negative_re = re.compile(r'Chrome.*Safari')

matcher = negative_re.search(sys.argv[1])
if matcher is None:
  print "match"
else:
  print "no match"

That seems easier to me.

Results:

mgilson@iris:~/sandbox$ python test.py "Like MAC OS Safari" 
match
mgilson@iris:~/sandbox$ python test.py "Chrome Mobile/12345 Safari" 
no match

Upvotes: 2

Related Questions