You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift Combine实现按优先级多字段分词前缀匹配搜索

解决方案

我们需要针对你的需求重新设计匹配逻辑,同时保留Combine流的原有架构,核心解决分词前缀匹配和短名优先两个核心要求:

1. 搜索词预处理工具函数

先将用户输入拆分为独立的搜索词,过滤无效空值并统一转小写,避免大小写和空格干扰:

func splitSearchTerms(_ input: String) -> [String] {
    return input.lowercased()
        .components(separatedBy: .whitespacesAndNewlines)
        .filter { !$0.isEmpty }
}

2. 前缀匹配判断逻辑

实现符合需求的匹配规则:检查所有搜索词是否都是目标字符串中任意单词的前缀(忽略大小写),比如输入brow chai时,brow匹配Brown的前缀、chai匹配Chair的前缀,就判定为匹配:

func matchesAllPrefixTerms(_ target: String, terms: [String]) -> Bool {
    let targetWords = target.lowercased().components(separatedBy: .whitespacesAndNewlines)
    return terms.allSatisfy { term in
        targetWords.contains { word in
            word.hasPrefix(term)
        }
    }
}

3. 整合到Combine流的最终实现

修改原函数,加入优先匹配短名的逻辑,只有短名无匹配结果时再匹配长名:

func editingChangedName(_ value: String) {
    $myName
        .debounce(for: 0.3, scheduler: RunLoop.main)
        .receive(on: DispatchQueue.global())
        .map { [weak self] filterString in
            guard let self = self else { return [] }
            let searchTerms = splitSearchTerms(filterString)
            
            // 保留原逻辑:输入长度不足3时返回空
            guard !searchTerms.isEmpty, filterString.count >= 3 else { return [] }
            
            // 第一步:优先匹配nameShort字段
            let shortNameMatches = self.nameArray.filter {
                matchesAllPrefixTerms($0.nameShort, terms: searchTerms)
            }
            
            // 短名有匹配结果直接返回,无结果再匹配长名
            guard shortNameMatches.isEmpty else { return shortNameMatches }
            
            // 第二步:匹配nameLong字段
            return self.nameArray.filter {
                matchesAllPrefixTerms($0.nameLong, terms: searchTerms)
            }
        }
        .receive(on: RunLoop.main)
        .assign(to: &$allNamesArray)
}

可选性能优化(大数据量场景)

如果nameArray数据量较大,可提前缓存每个条目拆分后的小写单词数组,避免重复计算:

struct dataSet: Codable, Hashable {
    let nameShort: String
    let nameLong: String
    
    // 缓存拆分后的小写单词数组
    lazy var lowercasedShortWords: [String] = {
        nameShort.lowercased().components(separatedBy: .whitespacesAndNewlines)
    }()
    
    lazy var lowercasedLongWords: [String] = {
        nameLong.lowercased().components(separatedBy: .whitespacesAndNewlines)
    }()
}

同步修改匹配函数:

func matchesAllPrefixTerms(_ targetWords: [String], terms: [String]) -> Bool {
    return terms.allSatisfy { term in
        targetWords.contains { $0.hasPrefix(term) }
    }
}

过滤时直接使用缓存数组:

let shortNameMatches = self.nameArray.filter {
    matchesAllPrefixTerms($0.lowercasedShortWords, terms: searchTerms)
}

内容的提问来源于stack exchange,提问作者kittonian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 12:48:23