我编写了一个简单的xml解析器。但是演出很糟糕。我不知道问题是什么,我的代码的瓶颈在哪里,这是由Swift 3.1在MacOS Sierra上编译的。
当我在一些XML文件(大约有43000个字符)上测试代码时,解析该文件大约需要4.5分钟!这是我的源代码:
class Parser {
let ignorableChars : [String] = [" ", "\"", "=", "\r", "\n", "\t"]
var i : Int
var xmlString : String
var stack : [Element]
init(xmlString: String) {
self.i = 0
self.xmlString = xmlString
self.stack = [Element]()
}
func ignoreProlog() -> Void {
while self.xmlString[self.i] != "<" {
self.i += 1
}
self.i += 1
if self.xmlString[self.i] == "?" {
self.i += 1
while self.xmlString[self.i] == "?" && self.xmlString[self.i + 1] == ">" {
self.i += 1
}
self.i += 2
}
else {
self.i -= 1
}
}
func ignoreMiscChars() -> Void {
while self.ignorableChars.contains(self.xmlString[self.i]) {
self.i += 1
}
}
func extractType() -> String {
var elementType : String = ""
while self.ignorableChars.contains(self.xmlString[self.i]) == false && self.xmlString[self.i] != ">" {
elementType.append(self.xmlString[self.i])
self.i += 1
}
return elementType
}
func extractKey() -> String {
var attrKey : String = ""
while self.ignorableChars.contains(self.xmlString[self.i]) == false && self.xmlString[self.i] != "/" && self.xmlString[self.i] != ">" {
attrKey.append(self.xmlString[self.i])
self.i += 1
}
return attrKey
}
func extractValue() -> String {
var attrValue : String = ""
while self.xmlString[self.i] != "\"" {
attrValue.append(self.xmlString[self.i])
self.i += 1
}
self.i += 1
return attrValue
}
func extractElement() -> (Element?, String?) {
while self.xmlString[self.i] != "<" {
self.i += 1
}
self.i += 1
if self.xmlString[self.i] == "/" {
self.i += 1
let elementType = self.extractType()
return (nil, elementType)
}
self.ignoreMiscChars()
let elementType = self.extractType()
var attributes = [String:String]()
while self.xmlString[self.i] != ">" && self.xmlString[self.i] != "/"{
self.ignoreMiscChars()
let key = self.extractKey()
if key == "" {
break
}
self.ignoreMiscChars()
let value = self.extractValue()
attributes[key] = value
}
let element = Element(type: elementType)
element.attributes = attributes
if self.xmlString[self.i] == "/" {
element.isCompleted = true
}
return (element, nil)
}
public func xmlParser() -> Element {
self.ignoreProlog()
while stack.isEmpty || stack[0].isCompleted == false {
let element = extractElement()
if element.0 == nil {
if element.1 == stack[0].type {
stack[0].isCompleted = true
break
}
let lastElement = stack.last
lastElement?.isCompleted = true
stack.removeLast()
stack[stack.endIndex - 1].chidren.append(lastElement!)
}
else if element.0?.isCompleted == true {
stack[stack.endIndex - 1].chidren.append(element.0!)
}
else {
stack.append(element.0!)
}
}
let root = stack.last
stack.removeAll()
return root!
}
}
最佳答案
尝试以下快速技巧,以确定字符串订阅(即self.xmlString[self.i]
)是否是您的瓶颈:
...
var i: Int
let xmlString: [Character]
var stack: [Element]
init(xmlString: String) {
self.i = 0
self.xmlString = Array(xmlString.characters)
self.stack = [Element]()
}
...
自由索引这样的
String
会很快破坏您的性能,考虑到所有Unicode重操作happening under the hood。相反,像上面的代码一样,将一次转换为
Character
数组可能会显著提高性能。索引一个数组是一个便宜的O(1)操作(即,恒定时间)。