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

如何让SwiftUI中的字符串匹配函数支持多关键词非连续匹配?

解决字符串多单词非连续匹配问题

这个问题很常见——localizedStandardContains(_:) 本质是检查完整子串是否连续存在,所以当目标文本里的两个单词中间插入了其他内容时,整个搜索字符串自然匹配不上。咱们来调整逻辑,让它能适配两种场景:

问题根源

localizedStandardContains 会严格匹配输入的整个字符串,比如你搜索的是 "like pineapple",它只会找连续出现这两个词的子串。但 fullTextLong 里这两个词中间有 "green",所以返回 false 是这个方法的预期行为,但不符合你的需求。

解决方案:拆分单词逐一匹配

我们可以把搜索文本拆成独立单词,然后验证每个单词都存在于目标文本中,同时保留 localizedStandardContains 的本地化匹配特性(比如忽略大小写、特殊字符的本地化处理)。

修改后的完整代码

struct ContainsFuncView: View {
    let fullTextShort = "I like pineapple"
    let fullTextLong = "I like green pineapple"
    let containsText = "like pineapple"
    
    var body: some View {
        VStack {
            contains(type: "Short")
            contains(type: "Long")
        }
    }
    
    func contains(type: String) -> Text {
        let targetText = type == "Short" ? fullTextShort : fullTextLong
        let containsInFullText = matchesAllSearchWords(containsText, in: targetText)
        
        return Text("\(containsInFullText ? "Contains" : "Doesn't contain") in fullText\(type)")
            .foregroundColor(containsInFullText ? .green : .red)
    }
    
    // 辅助函数:检查所有搜索单词是否都存在于目标文本中
    private func matchesAllSearchWords(_ searchText: String, in targetText: String) -> Bool {
        // 拆分搜索文本为单词数组,过滤掉空字符串(处理多空格情况)
        let searchWords = searchText.components(separatedBy: .whitespacesAndNewlines)
            .filter { !$0.isEmpty }
        
        // 如果搜索文本为空,默认返回true(可根据需求调整)
        guard !searchWords.isEmpty else { return true }
        
        // 逐一检查每个单词是否在目标文本中存在
        return searchWords.allSatisfy { targetText.localizedStandardContains($0) }
    }
}

进阶需求:按顺序匹配单词

如果你需要确保单词按指定顺序出现(比如不能是 "pineapple like"),可以改用正则表达式实现,允许单词中间存在任意内容:

private func matchesOrderedWords(_ searchText: String, in targetText: String) -> Bool {
    let searchWords = searchText.components(separatedBy: .whitespacesAndNewlines)
        .filter { !$0.isEmpty }
        .map { NSRegularExpression.escapedPattern(for: $0) }
    
    guard !searchWords.isEmpty else { return true }
    
    // 构建正则:单词之间允许任意内容(.*),忽略大小写
    let pattern = searchWords.joined(separator: ".*")
    let regex = try! NSRegularExpression(pattern: pattern, options: .caseInsensitive)
    
    let range = NSRange(targetText.startIndex..., in: targetText)
    return regex.firstMatch(in: targetText, options: [], range: range) != nil
}

只要把 contains 函数里的 matchesAllSearchWords 换成这个方法,就能确保 "like" 一定出现在 "pineapple" 之前,同时兼容中间有其他内容的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 05:18:24