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

swift regular expression extract
swift regular expression multiple matches
swift 5 regex capture group
regex non capturing group
nstextcheckingresult
swift regex validation
swift regex replace
xcode regular expression

I am using Swift 3 and trying to access captured groups.

let regexp = "((ALREADY PAID | NOT ALR | PROVIDER MAY | READY | MAY BILL | BILL YOU | PAID)((.|\\n)*))(( \\d+)(\\.+|-+)(\\d\\d))"

// check if some substring is in the recognized text
if let range = stringText.range(of:regexp, options: .regularExpression) {
    let result = tesseract.recognizedText.substring(with:range)
}

I want to be able to extract out the last two numbers captured (\d\d) so if the text was: ALREADY PAID asfasdfadsfasdf 39.15, it would extract 15. Here is a regex builder that shows what I want. Normally, I would be able to do $8 to get the 8th group that was extracted but I don't know how to do that in Swift 3.

http://regexr.com/3fh1e

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

How to capture Regex group values in Swift, Learn how to match and capture regular expression groups values in From that title we need to extract values “1” and “3” as a season and an  How to capture Regex group values in Swift. July 29, 2018 Today, I need to parse a string of a specific format and grab a couple of values from the string using Swift programming language. Sounds like a trivial problem. All I need to do is to use a regular expression to find the information I need.

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"

Regular Expressions in Swift, Regular expressions are a powerful tool for working with text, but it's often a a pattern more than once in a string or extract values from capture groups. 3, let firstCaptureRange = Range(match.range(at: 1), in: description),  Swift does not provide regex support in the language (hopefully in Swift 4!?). For now we still have to rely on NSRegularExpression.. Here is a String extension that extract the captured groups with a regex pattern.

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 Extract Regex Matches, How to check if my string matches with regex - Swift Swift regex: does a string match a pattern Duration: 4:35 Posted: Mar 14, 2019 Another nicety is how this pattern uses named capture groups (designated by (?<name>)) instead of the standard, positional capture groups from the previous example. Doing so allows us to access groups by name by calling the range (withName:) method on the match object.

NSRegularExpression, iOS 4.0+; macOS 10.7+; Mac Catalyst 13.0+; tvOS 9.0+; watchOS 2.0+ The ICU regular expressions supported by NSRegularExpression are described The example regular expression contains two capture groups, corresponding to the using the technique of template matching. Table 3 describes the syntax. Table 3. Escaped parentheses group the regex between them. They capture the text matched by the regex inside them into a numbered group that can be reused with a numbered backreference. They allow you to apply regex operators to the entire grouped regex. \(abc \) {3} matches abcabcabc. First group matches abc. no: no: no: no: no: no: no: no: no: no: no

Regex Tutorial, In a regular expression, parentheses can be used to group regex tokens together and for Capturing groups make it easy to extract part of the regex match. We can extract the matches, including the capture groups, as follows: for match in matches { for n in 0..<match.numberOfRanges { let range = match.rangeAtIndex(n) let r = testStr.startIndex.advancedBy(range.location) ..< testStr.startIndex.advancedBy(range.location+range.length) testStr.substringWithRange(r) } }

NSRegularExpression capture groups: Chord Symbols, How to use NSRegularExpression with capture groups in Swift. I want to parse chord symbols using a regular expression. the second is to determine how to use NSRegularExpression to retrieve matches from input. Let's make any of I, II​, III, V, VI, VII, VIII match by adding V zero or more times (using ?) Template - choose the group you would like to extract from the regular expression. '$1$' will extract group 1, '$2$' will extract group 2, and so on. $0$ will extract the entire expression.

Comments
  • Never use (.|\\n)*, just use .* and add a (?s) at the pattern start (or use the corresponding flag).
  • Use rangeAt(...). Examples here: stackoverflow.com/a/40952603/1187415 and here: stackoverflow.com/a/40040472/1187415 and here: stackoverflow.com/a/31817292/1187415
  • third is an NSRange, how do you convert it to the Range type required to use it in s.substring? or otherwise, where is the "h" result here? Is the only way to convert s to NSString? Is there a simpler way to use regex? This looks excessive.
  • @Efren NSRange to Range conversion for strings is a new Swift 4 feature.
  • Thanks @matt, I guess there's no simpler way until then.
  • @Efren It's annoying that regular expressions are a Cocoa feature, not a Swift feature, but that's how it is. And Cocoa thinks in NSString and NSRange, obviously. But in Swift 4 Range and NSRange are mutually coercible even for strings, so it's really no problem.
  • @Efren: With respect to NSRange/Range conversion in connection with NSRegularExpression, this Q&A might be of interest.