Swift 中正则表达式与元字符的不区分大小写和变音符号的匹配
Case and diacritic insensitive matching of regex with metacharacter in Swift
我正在尝试匹配用户输入中粗鲁的词,例如 "I Hate You!" 或 "i.håté.Yoù" 将与从 JSON 解析的词数组中的 "hate you" 匹配。
所以我需要它不区分大小写和变音符号,并将粗鲁单词中的空格视为任何非字母字符:
正则表达式元字符 \P{L}
应该适用,或者至少 \W
现在我知道 [cd]
可以与 NSPredicate
一起使用,就像这样:
func matches(text: String) -> [String]? {
if let rudeWords = JSON?["words"] as? [String]{
return rudeWords.filter {
let pattern = [=11=].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 = [=12=].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
和重音去除线,现在它工作正常即使它匹配的字符串比我最初想要的少。
链接
这些可能会帮助一些人处理正则表达式和谓词:
朝不同的方向前进可能是值得的。如果您更改正则表达式而不是展平输入,会怎样?
例如, 可以不与 hate.you
匹配,而是与 [h][åæaàâä][t][ëèêeé].[y][o0][ùu]
匹配(无论如何,这都不是一个全面的列表)。即时执行此转换(而不是存储它)是最有意义的,因为如果您以后需要更改字符扩展的内容,这可能会更容易。
这将使您能够更好地控制要匹配的字符。如果你看,我有 0
作为匹配 o
的字符。没有多少 Unicode 强制可以让你做到这一点。
我最终使用了 建议的解决方案。对我来说效果很好。
我post这里是为了任何可能需要它的人。
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])
}
}
我正在尝试匹配用户输入中粗鲁的词,例如 "I Hate You!" 或 "i.håté.Yoù" 将与从 JSON 解析的词数组中的 "hate you" 匹配。
所以我需要它不区分大小写和变音符号,并将粗鲁单词中的空格视为任何非字母字符:
正则表达式元字符 \P{L}
应该适用,或者至少 \W
现在我知道 [cd]
可以与 NSPredicate
一起使用,就像这样:
func matches(text: String) -> [String]? {
if let rudeWords = JSON?["words"] as? [String]{
return rudeWords.filter {
let pattern = [=11=].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 = [=12=].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
和重音去除线,现在它工作正常即使它匹配的字符串比我最初想要的少。
链接
这些可能会帮助一些人处理正则表达式和谓词:
朝不同的方向前进可能是值得的。如果您更改正则表达式而不是展平输入,会怎样?
例如, 可以不与 hate.you
匹配,而是与 [h][åæaàâä][t][ëèêeé].[y][o0][ùu]
匹配(无论如何,这都不是一个全面的列表)。即时执行此转换(而不是存储它)是最有意义的,因为如果您以后需要更改字符扩展的内容,这可能会更容易。
这将使您能够更好地控制要匹配的字符。如果你看,我有 0
作为匹配 o
的字符。没有多少 Unicode 强制可以让你做到这一点。
我最终使用了
我post这里是为了任何可能需要它的人。
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])
}
}