Regular Expressions in Swift

Our first program demonstrates the use of regular expressions in Swift. Here’s the full source code with explanations:

import Foundation

func main() {
    // This tests whether a pattern matches a string.
    let match = try! NSRegularExpression(pattern: "p([a-z]+)ch").firstMatch(in: "peach", range: NSRange(location: 0, length: 5)) != nil
    print(match)

    // For other regex tasks, you'll need to create a NSRegularExpression object.
    let regex = try! NSRegularExpression(pattern: "p([a-z]+)ch")

    // Many methods are available on these objects. Here's a match test like we saw earlier.
    print(regex.firstMatch(in: "peach", range: NSRange(location: 0, length: 5)) != nil)

    // This finds the match for the regex.
    if let match = regex.firstMatch(in: "peach punch", range: NSRange(location: 0, length: 11)) {
        print(NSString(string: "peach punch").substring(with: match.range))
    }

    // This also finds the first match but returns the start and end indexes for the match instead of the matching text.
    if let match = regex.firstMatch(in: "peach punch", range: NSRange(location: 0, length: 11)) {
        print("idx:", match.range)
    }

    // The 'Submatch' variants include information about both the whole-pattern matches and the submatches within those matches.
    if let match = regex.firstMatch(in: "peach punch", range: NSRange(location: 0, length: 11)) {
        let wholeMatch = NSString(string: "peach punch").substring(with: match.range)
        let subMatch = NSString(string: "peach punch").substring(with: match.range(at: 1))
        print([wholeMatch, subMatch])
    }

    // To find all matches for a regex
    let matches = regex.matches(in: "peach punch pinch", range: NSRange(location: 0, length: 17))
    print(matches.map { NSString(string: "peach punch pinch").substring(with: $0.range) })

    // Providing a limit to the number of matches
    let limitedMatches = regex.matches(in: "peach punch pinch", range: NSRange(location: 0, length: 17), options: [], range: NSRange(location: 0, length: 17))
    print(limitedMatches.prefix(2).map { NSString(string: "peach punch pinch").substring(with: $0.range) })

    // We can also use Data instead of String
    if let match = regex.firstMatch(in: String(data: "peach".data(using: .utf8)!, encoding: .utf8)!, range: NSRange(location: 0, length: 5)) {
        print(match.range.length > 0)
    }

    // When creating global variables with regular expressions, you can use the try! variant of initialization.
    let globalRegex = try! NSRegularExpression(pattern: "p([a-z]+)ch")
    print("regex:", globalRegex.pattern)

    // The NSRegularExpression can also be used to replace subsets of strings with other values.
    let modifiedString = regex.stringByReplacingMatches(in: "a peach", range: NSRange(location: 0, length: 7), withTemplate: "<fruit>")
    print(modifiedString)

    // The 'enumerateMatches' method allows you to transform matched text with a given closure.
    var result = "a peach"
    regex.enumerateMatches(in: result, range: NSRange(location: 0, length: result.count)) { (match, _, _) in
        if let match = match {
            let range = Range(match.range, in: result)!
            result = result.replacingCharacters(in: range, with: result[range].uppercased())
        }
    }
    print(result)
}

main()

To run this program, save it as a .swift file and use the Swift compiler or run it in a Swift playground.

$ swift regular-expressions.swift

For a complete reference on Swift regular expressions, check the NSRegularExpression class documentation in the Foundation framework.

Swift’s regular expression support is provided through the NSRegularExpression class from the Foundation framework. While the syntax and usage differ slightly from other languages, the core concepts remain the same.