Skip to content

Instantly share code, notes, and snippets.

@AliSoftware
Created July 31, 2019 13:46
Show Gist options
  • Save AliSoftware/96847470ae62489c7043cb0a098d1491 to your computer and use it in GitHub Desktop.
Save AliSoftware/96847470ae62489c7043cb0a098d1491 to your computer and use it in GitHub Desktop.
Simple wrapper around NSRegularExpression to provide a swiftier API and, ability to have matches exposing Range instead of NSRange
// Simple wrapper around NSRegularExpression to provide a swiftier API and, ability to have matches exposing Range instead of NSRange
import Foundation
struct RegEx {
let regex: NSRegularExpression
init(pattern: String, options: NSRegularExpression.Options = []) throws {
self.regex = try NSRegularExpression(pattern: pattern, options: options)
}
struct Match {
let fullString: String
let result: NSTextCheckingResult
var range: Range<String.Index> {
return self.range(at: 0)
}
var text: Substring {
return fullString[range]
}
var numberOfRanges: Int {
return result.numberOfRanges
}
func range(at index: Int) -> Range<String.Index> {
return Range(result.range(at: index), in: fullString)!
}
func range(named name: String) -> Range<String.Index> {
return Range(result.range(withName: name), in: fullString)!
}
subscript(index: Int) -> Substring {
return fullString[self.range(at: index)]
}
subscript(name: String) -> Substring {
return fullString[self.range(named: name)]
}
}
func matches(in string: String, options: NSRegularExpression.MatchingOptions = []) -> [Match] {
let nsrange = NSRange(string.startIndex... , in: string)
let results = self.regex.matches(in: string, options: options, range: nsrange)
return results.map { match in
Match(fullString: string, result: match)
}
}
}
extension RegEx: ExpressibleByStringLiteral {
init(stringLiteral value: String) {
try! self.init(pattern: value)
}
}
extension RegEx.Match: CustomStringConvertible {
var description: String {
return String(self.text)
}
}
extension RegEx.Match: CustomDebugStringConvertible {
var debugDescription: String {
let submatches: [String] = (0..<self.numberOfRanges).map {
let range = self.range(at: $0)
let start = fullString.distance(from: fullString.startIndex, to: range.lowerBound)
let end = fullString.distance(from: fullString.startIndex, to: range.upperBound)
return " - [\($0)]: [\(start)...\(end)] = \"\(self[$0])\""
}
return "RegEx.Match \"\(text)\"\n" + submatches.joined(separator: "\n")
}
}
//: ## Example usage
let list = "#Q23AS9D0APQQ2 Q23AS9D0APQQ2 #111111 #aaaaaa #q2IasK231@!@!#_+123 #asdas12312...1231@asda___213-1 #asdas123121231asda2131 asdas123121231asda2131"
let re = try! RegEx(pattern: #"#[a-z][a-z0-9]*\b"#, options: .caseInsensitive)
let results = re.matches(in: list)
results.forEach { print($0.debugDescription) }
/*
RegEx.Match "#Q23AS9D0APQQ2"
- [0]: [0...14] = "#Q23AS9D0APQQ2"
RegEx.Match "#aaaaaa"
- [0]: [37...44] = "#aaaaaa"
RegEx.Match "#q2IasK231"
- [0]: [45...55] = "#q2IasK231"
RegEx.Match "#asdas12312"
- [0]: [66...77] = "#asdas12312"
RegEx.Match "#asdas123121231asda2131"
- [0]: [98...121] = "#asdas123121231asda2131"
*/
print(results.map { $0.text })
/*
["#Q23AS9D0APQQ2", "#aaaaaa", "#q2IasK231", "#asdas12312", "#asdas123121231asda2131"]
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment