48

In Swift, what is a simple way to see if a string matches a pattern?

Pseudocode examples:

if string matches pattern ...

if string =~ pattern ...

(I have read the Swift docs and haven't seen a regex capability. I've read about adding a new =~ operator which is a good idea yet more complex than I'd like because this is for a teaching project. I have tried rangeOfString but get the error: 'String' does not have a member 'rangeOfString'. I am looking for a Swift solution, i.e. not typing NSRegularExpression. I do not need to do anything with the match result data.)

joelparkerhenderson
  • 34,808
  • 19
  • 98
  • 119
  • possible duplicate of [Swift Regex Matching](http://stackoverflow.com/questions/28776945/swift-regex-matching) – picciano Apr 21 '15 at 23:10
  • @picciano Thanks for the link - I added a clarification that this question is different than the linked one because I want to use just Swift terms, not NSRegularExpression. – joelparkerhenderson Apr 21 '15 at 23:52

4 Answers4

80

Swift version 3 solution:

if string.range(of: regex, options: .regularExpression, range: nil, locale: nil) != nil ...

Swift version 2 solution:

if string.rangeOfString(pattern, options: .RegularExpressionSearch) != nil ...

Example -- does this string contain two letter "o" characters?

"hello world".rangeOfString("o.*o", options: .RegularExpressionSearch) != nil

Note: If you get the error message 'String' does not have a member 'rangeOfString', then add this before: import Foundation. This is because Foundation provides the NSString methods that are automatically bridged to the Swift String class.

import Foundation

Thanks to Onno Eberhard for the Swift 3 update.

joelparkerhenderson
  • 34,808
  • 19
  • 98
  • 119
  • 1
    Why not use `regex.firstMatch(in: string, options: [], range: NSRange(location: 0, length: string.count)) != nil`? Isn't it semantically clearer than `range(of:options:range:locale:)`. – Iulian Onofrei Feb 11 '20 at 11:03
53

The solutions mentioned above didn't work for me anymore, so I'm posting my solution here (I used an extension for String):

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

Example:

if str.matches("^[a-zA-Z0-9._-]{1,30}$") {
    //...
}
Onno Eberhard
  • 1,341
  • 1
  • 10
  • 18
15

To get the syntax you actually ask about, you can easily define a new operator which wraps the bridged NSString functionality:

infix operator =~ {}
func =~(string:String, regex:String) -> Bool {
    return string.rangeOfString(regex, options: .RegularExpressionSearch) != nil
}

"abcd" =~ "ab*cd"
"abcd" =~ "abcde+"
David Berry
  • 40,941
  • 12
  • 84
  • 95
  • Thanks David. For this particular project I'm looking for a solution that doesn't define a new operator. (It would be great if Swift added your idea to the entire language, IMHO) – joelparkerhenderson Apr 22 '15 at 15:16
-1

In Swift 4.2 the following doesn't return nil even if the string does not match the pattern:

string.range(of: regex, options: .regularExpression, range: nil, locale: nil)

As Xcode suggests:

Comparing non-optional value of type 'NSRange' (aka '_NSRange') to nil always returns true

Therefore what I ended up using is:

if string.range(of: regex, options: .regularExpression)
        .location != NSNotFound {
    // do stuff if string matches regexp
}
Peter
  • 9
  • 3
  • 1
    You are calling that method on `NSString`, not on `String`, that's your problem. Your solution is technically correct for `NSString` but you can also just do `(string as String).range(of: ...) != nil`. – Sulthan Nov 02 '18 at 17:19