在搜索等场景,需要对完成的字符串进行分词处理,iOS 自带两种分词方式 NaturalLanguage
及 CFStringTokenizer
苹果这边 对于分词可以选择对于的模式,常用的是以词为单位,比如 工作质量会拆分成 工作和质量。当然 对于多语言来说,苹果这边支持的也较好,iOS 的Emoji也能识别出来。(特殊字符比如 , / ` 这些符合系统不会识别)
代码如下:
import Foundation
import NaturalLanguage
import CoreText
extension String {
public func NLTokenizer() -> [String] {
let tokenizer = NLTokenizer(unit: .word)
tokenizer.string = self
var keyWords: [String] = []
tokenizer.enumerateTokens(in: startIndex..<endIndex) { tokenRange, _ in
keyWords.append(String(self[tokenRange]))
return true
}
return keyWords
}
}
需要注意的是以上代码的运行结果并不包括系统未识别的的部分。
这里用CFStringTokenizer
单独给出包含原字符串所有的分词结果。
例如:今天天气不错,我们一起出去玩啊?
上面代码给出的结果是 今天 天气 不错 我们 一起 出去 玩 啊
下面代码给出的结果是 今天 天气 不错 , 我们 一起 出去 玩 啊 ?
extension String {
public func cStringTokenizer() -> [String] {
let cString = self as CFString
let nsString = self as NSString
let cStringCount = nsString.length
let ref = CFStringTokenizerCreate(
nil,
cString,
CFRangeMake(0, cStringCount),
kCFStringTokenizerUnitWord,
CFLocaleCopyCurrent()
)
CFStringTokenizerAdvanceToNextToken(ref)
var range: CFRange = CFStringTokenizerGetCurrentTokenRange(ref)
var keywords: [String] = []
var preTokenEndIndex: Int = -1
while range.length > 0 {
let defaultIndex = preTokenEndIndex + 1
if defaultIndex < range.location {
let ignoredRange = NSRange(
location: defaultIndex,
length: range.location - defaultIndex
)
let ignoredString = nsString
.substring(with: ignoredRange)
keywords.append(ignoredString)
}
preTokenEndIndex = range.location + range.length - 1
let keyWord = nsString
.substring(with: NSRange(location: range.location, length: range.length))
keywords.append(keyWord)
CFStringTokenizerAdvanceToNextToken(ref)
range = CFStringTokenizerGetCurrentTokenRange(ref)
}
if preTokenEndIndex + 1 < count {
let ignoredLocation = preTokenEndIndex + 1
let ignoredRange = NSRange(location: ignoredLocation, length: count - ignoredLocation)
let ignoredString = nsString
.substring(with: ignoredRange)
keywords.append(ignoredString)
}
return keywords
}
}