Regular expressions can be used to extract structured data from expected formats using capture groups. This post presents examples of using named and unnamed regular expression capture groups, also called regex capture groups, in Swift:
- Regex Capture Groups
a. Create ANSRegularExpression
b. Find Capture Groups
c. Extract Capture Groups - Named Regex Capture Groups
a. Create ANSRegularExpression
With Named Capture Groups
b. Find Named Capture Groups
c. Extract Named Capture Groups
Regex Capture Groups
Capture groups are a feature of regular expressions that allow data to be extracted from structured formats. For example, in the string "firstName middleName lastName"
the substring "firstName"
can be extracted using a capture group.
When creating a regular expression, use parentheses to form a capture group. In the following example, the first capture group is ([a-zA-Z-]+)
which matches one or more lowercase or uppercase letters.
Create A NSRegularExpression
let name = "firstName middleName lastName"
let nameRange = NSRange(
name.startIndex..<name.endIndex,
in: name
)
// Create A NSRegularExpression
let capturePattern = #"([a-zA-Z-]+) ?.* ([a-zA-Z-]+)?"#
let captureRegex = try! NSRegularExpression(
pattern: capturePattern,
options: []
)
Find Capture Groups
// Find the matching capture groups
let matches = captureRegex.matches(
in: name,
options: [],
range: nameRange
)
guard let match = matches.first else {
// Handle exception
throw NSError(domain: "", code: 0, userInfo: nil)
}
Extract Capture Groups
Capture groups are available as ranges on a NSTextCheckingResult
. Use numberOfRanges
to determine the number of matches and range(at:)
to get the NSRange
corresponding to the capture group at a specific index.
var names: [String] = []
// For each matched range, extract the capture group
for rangeIndex in 0..<match.numberOfRanges {
let matchRange = match.range(at: rangeIndex)
// Ignore matching the entire username string
if matchRange == nameRange { continue }
// Extract the substring matching the capture group
if let substringRange = Range(matchRange, in: name) {
let capture = String(name[substringRange])
names.append(capture)
}
}
names.first // firstName
names.last // lastName
Named Regex Capture Groups
Named regex capture groups enable access to capture groups using a name, instead of a range index. Named capture groups may improve code readability for complex regular expressions and regular expressions with multiple capture groups.
Create A NSRegularExpression With Named Capture Groups
let birthday = "01/02/2003"
let birthdayRange = NSRange(
birthday.startIndex..<birthday.endIndex,
in: birthday
)
// Create A NSRegularExpression
let capturePattern =
#"(?<month>\d{1,2})\/"# +
#"(?<day>\d{1,2})\/"# +
#"(?<year>\d{1,4})"#
let birthdayRegex = try! NSRegularExpression(
pattern: capturePattern,
options: []
)
Find Named Capture Groups
// Find the matching capture groups
let matches = birthdayRegex.matches(
in: birthday,
options: [],
range: birthdayRange
)
guard let match = matches.first else {
// Handle exception
throw NSError(domain: "", code: 0, userInfo: nil)
}
Extract Named Capture Groups
To get the NSRange
associated with a named capture group, pass the name of the capture group to range(withName:)
on a NSTextCheckingResult
.
var captures: [String: String] = [:]
// For each matched range, extract the named capture group
for name in ["month", "day", "year"] {
let matchRange = match.range(withName: name)
// Extract the substring matching the named capture group
if let substringRange = Range(matchRange, in: birthday) {
let capture = String(birthday[substringRange])
captures[name] = capture
}
}
captures["month"] // 01
captures["day"] // 02
captures["year"] // 2003
Regex Capture Groups in Swift
That’s it! By using NSRegularExpression
you can extract data using regex capture groups in Swift.