53

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.)

2
  • possible duplicate of Swift Regex Matching Commented Apr 21, 2015 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. Commented Apr 21, 2015 at 23:52

5 Answers 5

84

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.

Sign up to request clarification or add additional context in comments.

1 Comment

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:).
63

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}$") {
    //...
}

2 Comments

Check out reference, examples and live demo of Regular Expression at: regexr.com
You saved my 4 hours. The reusable method was so helpful.
16

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+"

1 Comment

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)
0

Swift 5.7 introduced regex literals, regex result builders (RegexBuilder) and better Swift types (Regex) and APIs for working with them. So (for example) you could match a whole string with something like this:

let decimalNumber = #/
    [+|-]?
    [0-9]([0-9_]*[0-9])?
    (\.[0-9]([0-9_]*[0-9])?)?
/#

if myString.wholeMatch(of: decimalNumber) != nil { /* myString is a decimal */ }

Note: You don't need to start the regex with ^ or end on $, as the wholeMatch method only matches the whole string its called on.

String also provides methods for matching the start of the string et cetera, and Regex provides a full suite of equivalent methods.

Note: If you right-click a regex in XCode, you can translate it to the RegexBuilder DSL. The builder is much more verbose, but can be a lot less cryptic in many cases (though sometimes it's worse).

Comments

-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
}

1 Comment

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.