【问题标题】:Extremely slow parsing text with Swift使用 Swift 解析文本非常慢
【发布时间】:2017-02-02 11:54:24
【问题描述】:

我正在尝试解析一个 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 秒触发一次日志,接下来的一千意味着 几乎 5 分钟 到达终点。整个过程应该需要几毫秒。这是怎么回事?有什么办法可以加快速度?

【问题讨论】:

  • 你想在这里完成什么?实际的解析是什么?
  • 我认为有更好的方法来查找子字符串。或者使用 Scanner 你可以分析一个字符串。
  • 考虑像github.com/tid-kijyun/Kanna这样的解析库

标签: ios swift string swift3 substring


【解决方案1】:

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. 获取子字符串(快速)

简而言之,对于起始位置n 的每个子字符串,算法必须遍历2n 字符。要获取索引20000 处的单个子字符串,您需要进行40000 操作!

【讨论】:

  • 谢谢,但这是一件很不舒服的事情。他们为什么用 String 制作一个链表:/
  • @user2976267 这不是一个链表。问题是字符没有相同的字节大小。其他语言的实现实际上是当今存在问题的语言。正如我在回答中所说,您始终可以在需要时获取字符数组,但自动执行此操作会大大影响性能。只需使用正确的原生函数即可。
猜你喜欢
  • 2016-08-12
  • 2011-12-18
  • 2013-09-03
  • 2015-04-28
  • 1970-01-01
  • 2016-04-07
  • 2016-03-26
  • 2015-08-26
  • 1970-01-01
相关资源
最近更新 更多