// // Copyright (c) 2019 Open Whisper Systems. All rights reserved. // import Foundation // ObjC compatible searcher @objc class AnySearcher: NSObject { private let searcher: Searcher public init(indexer: @escaping (AnyObject) -> String ) { searcher = Searcher(indexer: indexer) super.init() } @objc(item:doesMatchQuery:) public func matches(item: AnyObject, query: String) -> Bool { return searcher.matches(item: item, query: query) } } // A generic searching class, configurable with an indexing block public class Searcher { private let indexer: (T) -> String public init(indexer: @escaping (T) -> String) { self.indexer = indexer } public func matches(item: T, query: String) -> Bool { let itemString = normalize(string: indexer(item)) return stem(string: query).map { queryStem in return itemString.contains(queryStem) }.reduce(true) { $0 && $1 } } private func stem(string: String) -> [String] { var normalized = normalize(string: string) // Remove any phone number formatting from the search terms let nonformattingScalars = normalized.unicodeScalars.lazy.filter { !CharacterSet.punctuationCharacters.contains($0) } normalized = String(String.UnicodeScalarView(nonformattingScalars)) return normalized.components(separatedBy: .whitespacesAndNewlines) } private func normalize(string: String) -> String { return string.lowercased().trimmingCharacters(in: .whitespacesAndNewlines) } }