Regular Expressions in Swift: A Powerful Tool for Text Processing
Regular expressions (regex) are an indispensable tool for iOS and macOS developers. They allow you to perform complex search, replacement, and validation of text data using compact patterns. In Swift, working with regular expressions is implemented through the NSRegularExpression class from the Foundation framework. In this article, we will cover all aspects of using regex in Swift: from basic syntax to advanced techniques, with practical examples for iOS and macOS applications.
Basics of NSRegularExpression in Swift
To work with regular expressions in Swift, the NSRegularExpression class is used. It provides powerful methods for searching, replacing, and extracting data from strings. Let's look at the basic initialization syntax:
import Foundation
let pattern = "\\\\d{3}-\\\\d{2}-\\\\d{4}" // Pattern for SSNlet text = "My SSN: 123-45-6789"
do { let regex = try NSRegularExpression(pattern: pattern) let results = regex.matches(in: text, range: NSRange(text.startIndex..., in: text)) for match in results { let range = Range(match.range, in: text)! print("Found: \\(text[range])") }} catch { print("Error in regular expression: \\(error.localizedDescription)")}Note the escaping of backslashes in Swift strings. For each backslash in the pattern, you need to use two (\\\\d instead of \\d).
Creating and Configuring a Regular Expression
The NSRegularExpression constructor accepts an optional options parameter that allows you to configure the regex behavior:
.caseInsensitive— ignore character case.dotMatchesLineSeparators— dot matches newline characters.anchorsMatchLines— anchors ^ and $ work for each line.useUnixLineSeparators— use only as line separator
let regex = try NSRegularExpression( pattern: "swift", options: [.caseInsensitive])// Now the pattern will find "Swift", "SWIFT", "swift", etc.Searching and Extracting Data with regex
One of the main tasks of regular expressions is finding substrings that match a pattern. In Swift, this is done using the matches(in:options:range:) method.
Finding All Matches
let text = "Contacts: email@example.com, support@test.org, admin@site.com"let emailPattern = "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\\\.[A-Za-z]{2,}"
let regex = try NSRegularExpression(pattern: emailPattern)let matches = regex.matches(in: text, range: NSRange(text.startIndex..., in: text))
print("Emails found: \\(matches.count)")for match in matches { if let range = Range(match.range, in: text) { print(String(text[range])) }}// Output:// Emails found: 3// email@example.com// support@test.org// admin@site.comSearching with Group Capture
Groups in parentheses allow you to extract parts of a match. This is especially useful for parsing structured data:
let logLine = "2024-01-15 14:30:22 [ERROR] Failed to connect to server"let logPattern = "(\\\\d{4}-\\\\d{2}-\\\\d{2}) (\\\\d{2}:\\\\d{2}:\\\\d{2}) \\\\[(\\\\w+)\\\\] (.+)"
let regex = try NSRegularExpression(pattern: logPattern)if let match = regex.firstMatch(in: logLine, range: NSRange(logLine.startIndex..., in: logLine)) { let dateRange = Range(match.range(at: 1), in: logLine)! let timeRange = Range(match.range(at: 2), in: logLine)! let levelRange = Range(match.range(at: 3), in: logLine)! let messageRange = Range(match.range(at: 4), in: logLine)! print("Date: \\(logLine[dateRange])") print("Time: \\(logL