在Swift

时间:2016-01-26 15:23:55

标签: regex swift nspredicate nsregularexpression

我试图在用户输入中匹配粗鲁的单词,例如“我讨厌你!”或者“i.håté.Yoù”将与从JSON解析的单词数组中的“恨你”匹配。

所以我需要它是case和diacritic不敏感的,并将粗鲁的单词中的空格视为任何非字母字符: 正则表达式元字符\P{L}应该适用于此,或者至少\W

现在我知道[cd]适用于NSPredicate,就像这样:

 func matches(text: String) -> [String]? {
        if  let rudeWords = JSON?["words"] as? [String]{
            return rudeWords.filter {
                let pattern = $0.stringByReplacingOccurrencesOfString(" ", withString: "\\P{L}", options: .CaseInsensitiveSearch)
                    return NSPredicate(format: "SELF MATCHES[cd] %@", pattern).evaluateWithObject(text)
            }
        } else {
            log.debug("error fetching rude words")
            return nil
        }
    }

这不适用于任何元字符,我猜它们不会被NSpredicate解析,所以我尝试使用NSRegularExpression这样:

func matches(text: String) -> [String]? {
        if  let rudeWords = JSON?["words"] as? [String]{
            return rudeWords.filter {
                do {
                    let pattern = $0.stringByReplacingOccurrencesOfString(" ", withString: "\\P{L}", options: .CaseInsensitiveSearch)
                    let regex = try NSRegularExpression(pattern: pattern, options: .CaseInsensitive)
                    return regex.matchesInString(text, options: [], range: NSMakeRange(0, text.characters.count)).count > 0
                }
                catch _ {
                    log.debug("error parsing rude word regex")
                    return false
                }
            }
        } else {
            log.debug("error fetching rude words")
            return nil
        }
    }

这似乎工作正常但是我没有办法让正则表达式变音不敏感,所以我尝试了这个(以及其他解决方案,如重新编码)

let text = text.stringByFoldingWithOptions(.DiacriticInsensitiveSearch, locale: NSLocale.currentLocale())

然而,这对我来说不起作用,因为我每次输入一个字符时都会检查用户输入,所以我尝试删除重音的所有解决方案都会使应用程序变得非常慢。

有人知道是否有其他解决方案,或者我是否使用了错误的方式?

由于

修改

我实际上错了,使应用程序变慢的原因是尝试与\P{L}匹配,我尝试使用\W和重点剥离线进行第二次解决,现在即使它匹配的字符串少于我最初想要的字符串。

链接

这些可能会帮助一些处理正则表达式和谓词的人:

2 个答案:

答案 0 :(得分:2)

我最终使用了Laurel建议的解决方案。对我来说很好。

我在这里将其发布给任何可能需要它的人。

extension String {
    func getCaseAndDiacriticInsensitiveRegex() throws -> NSRegularExpression {
        var pattern = self.folding(options: [.caseInsensitive, .diacriticInsensitive], locale: .current)
        pattern = pattern.replacingOccurrences(of: "a", with: "[aàáâäæãåā]")
        pattern = pattern.replacingOccurrences(of: "c", with: "[cçćč]")
        pattern = pattern.replacingOccurrences(of: "e", with: "[eèéêëēėę]")
        pattern = pattern.replacingOccurrences(of: "l", with: "[lł]")
        pattern = pattern.replacingOccurrences(of: "i", with: "[iîïíīįì]")
        pattern = pattern.replacingOccurrences(of: "n", with: "[nñń]")
        pattern = pattern.replacingOccurrences(of: "o", with: "[oôöòóœøōõ]")
        pattern = pattern.replacingOccurrences(of: "s", with: "[sßśš]")
        pattern = pattern.replacingOccurrences(of: "u", with: "[uûüùúū]")
        pattern = pattern.replacingOccurrences(of: "y", with: "[yýÿ]")
        pattern = pattern.replacingOccurrences(of: "z", with: "[zžźż]")
        return try NSRegularExpression(pattern: pattern, options: [.caseInsensitive])
    }
}

答案 1 :(得分:1)

走向不同的方向可能是值得的。如果你改变了正则表达式怎么办?而不是扁平化输入?

不是与hate.you匹配,而是与[h][åæaàâä][t][ëèêeé].[y][o0][ùu]匹配,例如(在任何情况下,它都不是一个全面的列表)。如果您无法更改数据库中的条目,则可以在检索后将每个e替换为[ëèêeé]

这样可以更好地控制哪些字符匹配。如果你看,我0作为匹配o的字符。没有任何Unicode强制可以让你这样做。