使用Swift解析文本非常慢

时间:2017-02-02 11:54:24

标签: ios swift string swift3 substring

我试图解析一个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分钟才能结束。这个过程应该花费几毫秒。这笔交易是什么?有什么方法可以加快速度吗?

1 个答案:

答案 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个步骤组成:

  1. self.index(self.startIndex, offsetBy: start)从第一个字符开始迭代,直到找到索引为start的字符。
  2. self.index(self.startIndex, offsetBy: realEnd))从第一个字符开始迭代,直到找到索引为realEnd的字符。
  3. 获取子字符串(快速)
  4. 简而言之,对于起始位置n的每个子字符串,算法必须迭代2n个字符。要在索引20000获取单个子字符串,您需要40000次操作!