Last active
September 15, 2020 14:41
-
-
Save ollieatkinson/50b1259a2e4d84b6f3ba3181394fae03 to your computer and use it in GitHub Desktop.
Candy for NSRegularExpression matching. Match allows for indexed and named capture groups
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
extension NSRegularExpression { | |
@dynamicMemberLookup | |
public struct Match { | |
let string: String | |
let result: [NSTextCheckingResult] | |
private lazy var iterator = result.makeIterator() | |
public init(_ string: String, _ result: [NSTextCheckingResult]) { | |
self.string = string | |
self.result = result | |
} | |
} | |
public func matches(in string: String, options: MatchingOptions = []) -> Match { | |
.init(string, matches(in: string, options: options, range: string.nsRange)) | |
} | |
public func first(in string: String) -> Match? { | |
firstMatch(in: string, range: string.nsRange).map { .init(string, [$0]) } | |
} | |
public static func ~= (regex: NSRegularExpression, string: String) -> Bool { | |
regex.first(in: string) != nil | |
} | |
} | |
extension NSRegularExpression.Match { | |
public subscript<T>(dynamicMember keyPath: KeyPath<[NSTextCheckingResult], T>) -> T { | |
result[keyPath: keyPath] | |
} | |
} | |
extension NSRegularExpression.Match: Sequence, IteratorProtocol { | |
public mutating func next() -> NSTextCheckingResult? { | |
iterator.next() | |
} | |
} | |
extension NSRegularExpression.Match { | |
public subscript(name: String) -> String? { | |
result.lazy.map{ $0.range(withName: name) }.compactMap(string(at:)).first | |
} | |
public subscript(idx: Int) -> String? { | |
result.lazy.map{ $0.range(at: idx) }.compactMap(string(at:)).first | |
} | |
private func string(at ns: NSRange) -> String? { | |
guard ns.location != NSNotFound else { return nil } | |
guard let range = Range<String.Index>(ns, in: string) else { return nil } | |
return String(string[range]) | |
} | |
} | |
extension String { | |
public var regex: NSRegularExpression? { try? regex() } | |
public func regex(_ options: NSRegularExpression.Options = []) throws -> NSRegularExpression { | |
try NSRegularExpression(pattern: self, options: options) | |
} | |
} | |
extension String { | |
var nsRange: NSRange { | |
.init(location: 0, length: count) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment