Skip to content

Instantly share code, notes, and snippets.

@perlmunger
Created June 18, 2024 20:59
Show Gist options
  • Save perlmunger/4718fc1de2093c47e6283ca03cc1b21a to your computer and use it in GitHub Desktop.
Save perlmunger/4718fc1de2093c47e6283ca03cc1b21a to your computer and use it in GitHub Desktop.
Property to Convert String to Shipper URL if Tracking Number Matches Regex
import UIKit
infix operator =~
func =~ (value : String, pattern : String) -> RegexMatchResult {
var err : NSError?
let nsstr = value as NSString
let options = NSRegularExpression.Options(rawValue: 0)
let re: NSRegularExpression?
do {
re = try NSRegularExpression(pattern: pattern, options: options)
} catch let error as NSError {
err = error
re = nil
}
if let _ = err {
return RegexMatchResult(items: [])
}
let all = NSRange(location: 0, length: nsstr.length)
let moptions = NSRegularExpression.MatchingOptions(rawValue: 0)
var matches = [String]()
re!.enumerateMatches(in: value, options: moptions, range: all) {
(result : NSTextCheckingResult?, flags : NSRegularExpression.MatchingFlags, ptr : UnsafeMutablePointer<ObjCBool>) in
let string = nsstr.substring(with: result!.range)
matches.append(string)
}
return RegexMatchResult(items: matches)
}
struct RegexMatchCaptureGenerator : IteratorProtocol {
mutating func next() -> String? {
if items.isEmpty { return nil }
let ret = items[0]
items = items[1..<items.count]
return ret
}
var items: ArraySlice<String>
}
struct RegexMatchResult : Sequence {
var items: [String]
func makeIterator() -> RegexMatchCaptureGenerator {
return RegexMatchCaptureGenerator(items: items[0..<items.count])
}
var boolValue: Bool {
return items.count > 0
}
subscript (i: Int) -> String {
return items[i]
}
}
extension String {
var shippingLink : URL? {
let shippers =
["fedex" : ["regex" : "(\\b96\\d{20}\\b)|(\\b\\d{15}\\b)|(\\b\\d{12}\\b)",
"tracking_url" : "http://fedex.com/Tracking?action=track&language=english&cntry_code=us&tracknumbers=%@",
"name" : "FedEx"],
"ups" : ["regex" : "\\b(1Z ?[0-9A-Z]{3} ?[0-9A-Z]{3} ?[0-9A-Z]{2} ?[0-9A-Z]{4} ?[0-9A-Z]{3} ?[0-9A-Z]|[\\dT]\\d\\d\\d ?\\d\\d\\d\\d ?\\d\\d\\d)\\b",
"tracking_url" : "http://wwwapps.ups.com/etracking/tracking.cgi?InquiryNumber1=%@&TypeOfInquiryNumber=T&AcceptUPSLicenseAgreement=yes&submit=Track",
"name" : "UPS"],
"usps" : ["regex" : "\\b(9\\d\\d\\d ?\\d\\d\\d\\d ?\\d\\d\\d\\d ?\\d\\d\\d\\d ?\\d\\d\\d\\d ?\\d\\d|91\\d\\d ?\\d\\d\\d\\d ?\\d\\d\\d\\d ?\\d\\d\\d\\d ?\\d\\d\\d\\d)\\b",
"tracking_url" : "http://trkcnfrm1.smi.usps.com/PTSInternetWeb/InterLabelInquiry.do?origTrackNum=%@",
"name" : "US Postal Service"],
"purolator" : ["regex" : "\\b((ANR|BXF|DCM|CGJ|YAW)[0-9]{9})\\b",
"tracking_url" : "https://www.purolator.com/purolator/ship-track/tracking-summary.page?pin=%@",
"name" : "Purolator"],
"spee-dee" : ["regex" : "(SP\\d+)\\b",
"tracking_url" : "http://packages.speedeedelivery.com/index.php?barcodes=%@",
"name" : "Spee-Dee Delivery Service"]
]
for (_, value) in shippers {
// If the regex matches, build out the URL
for _ in self =~ value["regex"]! {
// Interpolate self (the tracking number) into the url String
let urlString = String(format: (value["tracking_url"]!), self)
// Return the resulting URL
return URL(string: urlString)
}
}
return nil
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment