Capturing groups of information with regex in Swift 5

Using regular expressions in Swift isn’t terribly painless, but I wrote a helper function for capturing groups of information and thought it was useful in general.

func searchStringForRegex(string: String, regex: String, captureGroups: [String]) -> [String: String] {
  let strRange = NSRange(string.startIndex..<string.endIndex, in: string)
  let nameRegex = try! NSRegularExpression(pattern: regex, options: [])
        
  var captures: [String: String] = [:]
        
  let matches = nameRegex.matches(in: string, options: [], range: strRange)
        
  for match in matches {
    for name in captureGroups {
      let matchRange = match.range(withName: name)
                
      if let substringRange = Range(matchRange, in: string) {                 
        captures[name] = String(string[substringRange])
      }
    }
  }
        
  return captures
}

This function takes 3 arguments. The string you want to search is string, the regular expression is regex, and captureGroups is an array of strings. The array captureGroups is a collection of your named groups defined in your regular expression. searchStringForRegex expects you to use named groups in your regular expression.

This is how you would use the function:

let string = "name is Jane Doe"
let nameCapturePattern = #"name\s?is\s?(?<firstName>\S+)\s?(?<lastName>\S+)"#
let captureGroups = ["firstName", "lastName"]
            
let captures = self.searchStringForRegex(string: string, regex:    
                           nameCapturePattern, captureGroups: captureGroups)
            
if captures["firstName"] != nil && captures["lastName"] != nil {
  print("\(captures["firstName"]!) \(captures["lastName"]!)"
}

Define your named groups in your regular expression, here I’m storing the regex in nameCapturePattern. Use those same names in a string array (captureGroups). When you call the function it will return a dictionary of strings (captures), with the name of the regex group being the key and the matched string being the value.

We check to see if the matches are nil, because the regular expression might not match anything. In the print statement, the values interpolated are force-unwrapped with ! because we’ve already checked whether the values are nil with the if statement. This force-unwrapping is safe because of the if statement.