Skip to content

Instantly share code, notes, and snippets.

@JulianAlonso
Last active March 7, 2023 06:22
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save JulianAlonso/fcc6976abee9408e7e9f345aeb72584b to your computer and use it in GitHub Desktop.
Save JulianAlonso/fcc6976abee9408e7e9f345aeb72584b to your computer and use it in GitHub Desktop.
Mapping URL (Deep linking) on iOS.
import Foundation
extension String {
//Know if self is only composed by numbers
var isNumber: Bool {
return !self.isEmpty && CharacterSet.decimalDigits.isSuperset(of: CharacterSet(charactersIn: self))
}
}
//Struct to check Regular Expresions
struct Regex {
let pattern: String
let options: NSRegularExpression.Options!
private var matcher: NSRegularExpression {
return try! NSRegularExpression(pattern: self.pattern, options: self.options)
}
init(_ pattern: String, options: NSRegularExpression.Options = [.caseInsensitive]) {
self.pattern = pattern
self.options = options
}
//Devuelve el array de grupos
func match(_ string: String, options: NSRegularExpression.MatchingOptions = []) -> [NSTextCheckingResult] {
return self.matcher.matches(in: string, options: [], range: NSMakeRange(0, string.characters.count))
}
}
//Implement this in whatever type you want to check with regular expresions
protocol RegexMatchable {
func match(regex: Regex) -> Bool
}
//Wrap the comparing string and the groups to extract ids
final class Matcher: RegexMatchable {
let comparing: String
var groups: [NSTextCheckingResult]?
var matchingGroups: [String] {
var matches = [String]()
if let groups = groups {
let string = comparing as NSString
for group in groups {
for index in 1..<group.numberOfRanges {
matches.append(string.substring(with: group.rangeAt(index)))
}
}
}
return matches
}
var intGroups: [Int] {
return self.matchingGroups.flatMap { Int($0) }
}
init(_ matching: String) {
self.matching = matching
}
func match(regex: Regex) -> Bool {
let matches = regex.match(self.matching)
if !matches.isEmpty {
self.groups = matches
return true
}
return false
}
}
extension String: RegexMatchable {
func match(regex: Regex) -> Bool {
return !regex.match(self).isEmpty
}
}
//Overload patter matching operator
func ~=<T>(pattern: Regex, matchable: T) -> Bool where T: RegexMatchable {
return matchable.match(regex: pattern)
}
//Routing with enums its easy
enum DeepLinking {
case helado(id: Int)
}
func linking(_ path: String) -> DeepLinking? {
let matching = Matcher(path)
switch matching {
case Regex("^(\\/helado\\/([0-9]+)\\/*)"):
guard let id = matching.intGroups.first else { return nil }
//Here you have your id, typed.
return .helado(id: id)
default:
//No matches
return nil
}
}
let link = linking("/helado/43") //.helado(43)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment