Swift 给一段话分句,或将一句话关键词分组
2018-08-15 本文已影响74人
四月_Hsu
场景
目前正在做阅读器听书功能,集成了百度语音后,每次要给语音SDK传入一句话,然后得到语音。但是有长度限制。为了语音流畅,需要将一章文字按句分组,之后管理一个队列数组,用于语音功能。
如何给一段话分句
实践一:使用 Sting
的 components(separatedBy: )
方法
其实最开始是想通过正则表达式分组,最终未能实现。之后使用该方法。其实分组不仅仅可以传入单个字符,也能传入一个字符组:
components(separatedBy: <#T##StringProtocol#>)
components(separatedBy: <#T##CharacterSet#>)
这个也是我最初采用的方法。但是之后发现存在比较严重的问题,并且并未解决。
存在问题:首先,分组后的语句是不包含作为分隔符的标点符号的,这样对于阅读器切页时每页的 Range
就产生了影响,没法精确判断读到该页末尾时翻页、翻章。其次,阅读文字时需要字体高亮,但是通过该方法分组后的语句,对于作为分隔符的标点符号,如果紧邻其他符号,其他符号为氛围下一句,最典型的就是 。”
,分组后,下引号会分到下一句,明显很难看。
实现代码如下:
let str = "我说:“这是一句话。”而且按照现在的情况来看,这个奥术还是特别加强了稳固性和构成速度!顷刻之间就要爆发了。“混蛋……居然是这样的陷阱…”女法师脸上浮现出了悲愤,无奈,绝望。"
let matchs = str.components(separatedBy: CharacterSet.init(charactersIn: " 。!?;\n "))
matchs.forEach { (s) in
print("🌞 --- \(s)")
}
控制台输出:
🌞 --- 我说:“这是一句话
🌞 --- ”而且按照现在的情况来看,这个奥术还是特别加强了稳固性和构成速度
🌞 --- 顷刻之间就要爆发了
🌞 --- “混蛋……居然是这样的陷阱…”女法师脸上浮现出了悲愤,无奈,绝望
🌞 ---
存在问题显而易见,尤其是需要这句话高亮时,问题更明显。由此,查资料时找到了第二种方法。
实践二:采用原生 API 接口 CFStringTokenizer
CFStringTokenizer
功能很强大,之前也从未使用过,这里也只是通过查询一些博客,采用了自己需要的一点功能。
let str = "我说:“这是一句话。”而且按照现在的情况来看,这个奥术还是特别加强了稳固性和构成速度!顷刻之间就要爆发了。“混蛋……居然是这样的陷阱…”女法师脸上浮现出了悲愤,无奈,绝望。"
let ref = CFStringTokenizerCreate(nil, str as CFString, CFRangeMake(0, str.lenght), kCFStringTokenizerUnitSentence, nil)
CFStringTokenizerAdvanceToNextToken(ref)
var range: CFRange
range = CFStringTokenizerGetCurrentTokenRange(ref)
// 循环
var sentence = ""
var sentences = [String]()
while range.length > 0 {
sentence = str.substring(NSMakeRange(range.location, range.length))
sentences.append(sentence)
CFStringTokenizerAdvanceToNextToken(ref)
range = CFStringTokenizerGetCurrentTokenRange(ref)
print("🦁 \(sentence)")
}
控制台输出:
🦁 我说:“这是一句话。”
🦁 而且按照现在的情况来看,这个奥术还是特别加强了稳固性和构成速度!
🦁 顷刻之间就要爆发了。“
🦁 混蛋……居然是这样的陷阱…”女法师脸上浮现出了悲愤,无奈,绝望。
是不是符合预期的结果直接就出来了。。暂时效果如下图:
听书
如果修改属性 kCFStringTokenizerUnitSentence
为 kCFStringTokenizerUnitWord
,就是按照关键词分组了。其实这个属性还有其他各种设置,具体使用时可以根据需要修改。
另外,关键词分组效果类似:
🦁 我
🦁 说
🦁 这
🦁 是
🦁 一
🦁 句
🦁 话
🦁 而且
🦁 按照
🦁 现在
🦁 的
如何暂停倒计时
这个也是刚刚用到的一个方法。一旦 timer.invalidate()
后,并不能在开启了。下面是一个简单的计时器实现:
// MARK: - 计时器
@IBOutlet weak var timeView: UIView!
@IBOutlet weak var timeLabel: UILabel!
private var countdownTimer: Timer?
private var durtion: Int = 0
// 开始
@IBAction func startTimerAction(_ sender: UIButton) {
if countdownTimer == nil {
countdownTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(countdown), userInfo: nil, repeats: true)
}
durtion = 0
}
// 暂停
@IBAction func pauseTimerAction(_ sender: UIButton) {
countdownTimer?.fireDate = Date.distantFuture
}
// 继续
@IBAction func resumeTimerAction(_ sender: UIButton) {
countdownTimer?.fireDate = Date.distantPast
}
// 停止
@IBAction func stopTimerAction(_ sender: UIButton) {
countdownTimer?.invalidate()
countdownTimer = nil
}
// 计时
@objc private func countdown() {
durtion += 1
let delaySeconds = 30 * 60 - durtion
let minutes = delaySeconds / 60
let seconds = delaySeconds % 60
let timeStr = String(format: "%02d:%02d", arguments: [minutes, seconds])
timeLabel.text = timeStr
}