Swift 3 - How do I extract captured groups in regular expressions?

but I don't know how to do that in Swift 3.

When you receive a match from NSRegularExpression, what you get is an NSTextCheckingResult. You call rangeAt to get a specific capture group.

Example:

let s = "hey ho ha"
let pattern = "(h).*(h).*(h)"
// our goal is capture group 3, "h" in "ha"
let regex = try! NSRegularExpression(pattern: pattern)
let result = regex.matches(in:s, range:NSMakeRange(0, s.utf16.count))
let third = result[0].rangeAt(3) // <-- !!
third.location // 7
third.length // 1

As ever, a simple extension seems to be the way around swift's bizarre overcomplication...

extension NSTextCheckingResult {
    func groups(testedString:String) -> [String] {
        var groups = [String]()
        for i in  0 ..< self.numberOfRanges
        {
            let group = String(testedString[Range(self.range(at: i), in: testedString)!])
            groups.append(group)
        }
        return groups
    }
}

Use it like this:

if let match = myRegex.firstMatch(in: someString, range: NSMakeRange(0, someString.count)) {
     let groups = match.groups(testedString: someString)
     //... do something with groups
}

Swift 4, Swift 5

extension String {
    func groups(for regexPattern: String) -> [[String]] {
    do {
        let text = self
        let regex = try NSRegularExpression(pattern: regexPattern)
        let matches = regex.matches(in: text,
                                    range: NSRange(text.startIndex..., in: text))
        return matches.map { match in
            return (0..<match.numberOfRanges).map {
                let rangeBounds = match.range(at: $0)
                guard let range = Range(rangeBounds, in: text) else {
                    return ""
                }
                return String(text[range])
            }
        }
    } catch let error {
        print("invalid regex: \(error.localizedDescription)")
        return []
    }
}
}

example:

let res = "1my 2own 3string".groups(for:"(([0-9]+)[a-z]+) ")

(lldb) po res ▿ 2 elements
▿ 0 : 3 elements

- 0 : "1my "

- 1 : "1my"

- 2 : "1"   

▿ 1 : 3 elements

- 0 : "2own "

- 1 : "2own"

- 2 : "2"