我试图解析一个46k字符的文本文档,这需要永远这样做。这就是我的所作所为:
for i in 0..<html.length() - SEARCH_START.length() {
if html.substring(i, end: i+SEARCH_START.length()) == SEARCH_START {
start = i + SEARCH_START.length();
break;
}
if i % 1000 == 0 {
NSLog("i = \(i)")
}
}
extension String {
public func length () -> Int {
return self.characters.count
}
public func substring(_ start : Int, end : Int) -> String {
if self.characters.count <= 0 {
return ""
}
let realEnd = end>0 ? end : 0
return self.substring(with: self.index(self.startIndex, offsetBy: start)..<self.index(self.startIndex, offsetBy: realEnd))
}
}
抱歉,必须扩展String类才能减少从Android重写的次数。 因此,每隔6.5秒触发一次Log,接下来的千分之一意味着差不多5分钟才能结束。这个过程应该花费几毫秒。这笔交易是什么?有什么方法可以加快速度吗?
答案 0 :(得分:2)
您Int
索引扩展名是问题所在。要获得位置n
的子字符串,需要遍历所有字符0..n
。因此,您的算法具有O(n^2)
(二次)复杂度,而不是预期的O(n)
(线性)复杂度。
不要使用该扩展程序。
要搜索子字符串,有一个本机方法
if let range = html.range(of: SEARCH_START) {
let integerIndex = html.distance(from: html.startIndex, to: range.upperBound)
print(integerIndex)
}
如果您真的想使用整数,则应首先将字符串转换为字符数组:
let chars = Array(html.characters)
并使用子数组而不是子字符串。
编辑:
要更好地了解您的扩展程序中发生了什么:
self.substring(with: self.index(self.startIndex, offsetBy: start)..<self.index(self.startIndex, offsetBy: realEnd))
在Java中,String
是一个数组并且支持随机索引,这将是一个常量(快速)操作。但是,在Swift中,这由3个步骤组成:
self.index(self.startIndex, offsetBy: start)
从第一个字符开始迭代,直到找到索引为start
的字符。self.index(self.startIndex, offsetBy: realEnd))
从第一个字符开始迭代,直到找到索引为realEnd
的字符。简而言之,对于起始位置n
的每个子字符串,算法必须迭代2n
个字符。要在索引20000
获取单个子字符串,您需要40000
次操作!