Brett
Brett

Reputation: 1837

Cannot get Regex in Swift to match "not containing"

I cannot seem to get the following regular expression to work. It should match when the string does not start with "quick:". This regular expression string comes from the backend, I may be able to get it changed, but I can't change it to a prefix test in code as any regex can be used.

I tried using .range( of):

extension String {
    func regexMatch(_ pattern: String) -> Bool {
        return self.range(of: pattern, options: .regularExpression) != nil
    }
}

XCTAssertTrue("No".regexMatch(#"/^(?!quick:)/"#) )       // Fails
XCTAssertFalse("quick:No".regexMatch(#"/^(?!quick:)/"#)) // Passes

But the first test fails. So I tried NSRegularExpression

extension String {    
    // https://gist.github.com/torinkwok/799784dc28fd85e4751b935696030a1d
    func match(_ pattern: String, options: NSRegularExpression.Options = []) throws -> Bool {

        let regex = try NSRegularExpression(pattern: pattern, options: options)
        return regex.numberOfMatches(in: self,
                                     options: [],
                                     range: NSRange(location: 0, length: 0.distance(to: utf16.count))) != 0
    }
}

XCTAssertTrue(try "No".match(#"/^(?!quick:)/"#) )       // Fails
XCTAssertFalse(try "quick:No".match(#"/^(?!quick:)/"#)) // Passes

And this also fails. I plugged the Regex into an online regex checker to ensure it works and it does. Can anyone shed some light onto why this doesn't work in Swift ?

Upvotes: 0

Views: 730

Answers (1)

HalR
HalR

Reputation: 11073

I'm not sure what the purpose of the #'s and \"'s were in the strings, but simplifying the regex works just fine in this playground I made:

import UIKit
var str = "Hello, playground"
extension String {
    // https://gist.github.com/torinkwok/799784dc28fd85e4751b935696030a1d
    func match(_ pattern: String, options: NSRegularExpression.Options = []) throws -> Bool {

        let regex = try NSRegularExpression(pattern: pattern, options: options)
        return regex.numberOfMatches(in: self,
                                     options: [],
                                     range: NSRange(location: 0, length: 0.distance(to: utf16.count))) != 0
    }
}

let shouldBeTrue = try "No".match("^(?!quick:)")
let shouldBeFalse = try "quick:No".match("^(?!quick:)")

Upvotes: 2

Related Questions