Skip to content

Instantly share code, notes, and snippets.

@trszdev
Last active June 14, 2023 15:55
Show Gist options
  • Save trszdev/01c68b2cfd70f5a057be3c65dffa07d0 to your computer and use it in GitHub Desktop.
Save trszdev/01c68b2cfd70f5a057be3c65dffa07d0 to your computer and use it in GitHub Desktop.
Allows convenient navigation between capture groups for NSRegularExpression
import Foundation
public final class RegexGroup: CustomDebugStringConvertible {
public internal(set) var subgroups = [RegexGroup]()
public internal(set) var value = Substring()
func contains(range: Range<String.Index>) -> Bool {
return range.lowerBound >= value.startIndex && range.upperBound <= value.endIndex
}
public var debugDescription: String { "RegexGroup(\(value))" }
}
extension NSTextCheckingResult {
func group(in value: String) -> RegexGroup? {
var stack = [RegexGroup]()
for i in 0..<numberOfRanges {
let nsRange = self.range(at: i)
guard nsRange.location != NSNotFound else { continue }
let startIndex = value.index(value.startIndex, offsetBy: nsRange.location)
let endIndex = value.index(startIndex, offsetBy: nsRange.length)
let range = startIndex..<endIndex
guard !range.isEmpty else { continue }
let group = RegexGroup()
group.value = value[range]
while var parentGroup = stack.last, !parentGroup.contains(range: range) {
stack.popLast()
}
stack.last?.subgroups.append(group)
stack.append(group)
}
return stack.first
}
}
extension NSRegularExpression {
func firstGroup(in string: String) -> RegexGroup? {
let stringRange = NSRange(location: 0, length: string.count)
return firstMatch(in: string, range: stringRange)?.group(in: string)
}
func allGroups(in string: String) -> [RegexGroup] {
let stringRange = NSRange(location: 0, length: string.count)
return matches(in: string, range: stringRange).compactMap { $0.group(in: string) }
}
}
let timePattern = #"((\d{2})((\d{2}))((F)(\d*))?)"#
let regex = try! NSRegularExpression(pattern: timePattern)
dump(regex.allGroups(in: "1900F-1800"))
dump(regex.firstGroup(in: "1234F3"))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment