← Back to index

AddressHelpers

Spots
CodeWhat It DoesHow It Does It
▶ IMPORTS
import FoundationFramework importsImports Foundation.
enum AddressHelper { // MARK: - Borough detection static let boroughOrder = ["Manhattan", "Brooklyn", "Queens", "Bronx", "Staten Island"] /// Derives the conventional postal borough/city name from an address string. static func borough(for address: String) -> String { // Strip trailing ", United States" / ", USA" that Apple Maps sometimes appends. var raw = address for suffix in [", United States", ", USA"] where raw.hasSuffix(suffix) { raw = String(raw.dropLast(suffix.count)).trimmingCharacters(in: .whitespaces) break } let pattern = #",\s*([^,]+),\s*[A-Za-z]{2,}(?:\s+\d{5}(?:-\d{4})?)?\s*$"# guard let regex = try? NSRegularExpression(pattern: pattern), let match = regex.firstMatch(in: raw, range: NSRange(raw.startIndex..., in: raw)), let range = Range(match.range(at: 1), in: raw) else { return "Other" } let city = String(raw[range]).trimmingCharacters(in: .whitespaces) switch city.lowercased() { case "new york", "new york city", "manhattan": return "Manhattan" case "brooklyn": return "Brooklyn" case "queens", "astoria", "long island city", "flushing", "jamaica", "forest hills": return "Queens" case "bronx", "the bronx": return "Bronx" case "staten island": return "Staten Island" default: return city.isEmpty ? "Other" : city } } // MARK: - Address migration /// Cleans up an address string the same way EntryStore.load() does on disk. /// Safe to call repeatedly — idempotent. static func migratedAddress(_ address: String) -> String { var addr = address // 1. Strip trailing ", United States" / ", USA" for suffix in [", United States", ", USA"] where addr.hasSuffix(suffix) { addr = String(addr.dropLast(suffix.count)).trimmingCharacters(in: .whitespaces) break } // 2. "Manhattan, NY" → "New York, NY" addr = addr.replacingOccurrences( of: "Manhattan, NY", with: "New York, NY", options: .caseInsensitive) return addr } // MARK: - Search matching /// Returns true when the entry matches the given (possibly empty) search query. static func matches(entry: SpotEntry, query: String) -> Bool { guard !query.isEmpty else { return true } let q = query.lowercased() return entry.playName.lowercased().contains(q) || entry.cuisine.lowercased().contains(q) || entry.neighborhood.lowercased().contains(q) || entry.notes.lowercased().contains(q) } // MARK: - Entry sorting (pure, no location dependency) /// Sorts entries by the given order. Distance sort falls back to alphabetical /// (the caller must supply pre-sorted entries when a live location is available). static func sort(_ entries: [SpotEntry], by order: SortOrder) -> [SpotEntry] { switch order { case .default: return entries.sorted { $0.playName.lowercased() < $1.playName.lowercased() } case .cuisine: return entries.sorted { $0.cuisine.lowercased() < $1.cuisine.lowercased() } case .neighborhood: return entries.sorted { $0.neighborhood.lowercased() < $1.neighborhood.lowercased() } case .distance: return entries.sorted { $0.playName.lowercased() < $1.playName.lowercased() } case .ratings: return entries.sorted { $0.starRating > $1.starRating } } } }`AddressHelper` enumDefines the `AddressHelper` enum.