在Swift中将字符串解析为对象
我已收到来自服务器的此响应,我确信一定有更有效的方法将其转换为对象。在Swift中将字符串解析为对象,swift,Swift,我已收到来自服务器的此响应,我确信一定有更有效的方法将其转换为对象。 我有以下回应: [ id=2997,rapidViewId=62,state=ACTIVE,name=Sprint7,startDate=2018-11-20T10:28:37.256Z,endDate=2018-11-30T10:28:00.000Z,completeDate=<null>,sequence=2992,goal=none ] 不确定您想要什么格式,但下面的代码将生成一个元组数组(key,valu
我有以下回应:
[
id=2997,rapidViewId=62,state=ACTIVE,name=Sprint7,startDate=2018-11-20T10:28:37.256Z,endDate=2018-11-30T10:28:00.000Z,completeDate=<null>,sequence=2992,goal=none
]
不确定您想要什么格式,但下面的代码将生成一个元组数组(key,value),但所有值都是字符串,因此我想以后需要进行另一次转换
let items = stringOutput.components(separatedBy: ",").compactMap( {pair -> (String, String) in
let keyValue = pair.components(separatedBy: "=")
return (keyValue[0], keyValue[1])
})
这是一项减少工作:
let keyValueStrings = yourString.components(separatedBy: ",")
let dictionary = keyValueStrings.reduce([String: String]()) {
(var aggregate: [String: String], element: String) -> [String: String] in
let elements = element.componentsSeparatedByString("=")
let key = elements[0]
// replace nil with the value you want to use if there is no value
let value = (elements.count > 1) ? elements[1] : nil
aggregate[key] = value
return aggregate
}
这是一种功能性方法,但您可以使用for迭代实现相同的功能。
所以你可以使用Swift的基本映射方法。例如,您将拥有自定义对象结构。首先,您将向其添加一个init方法。然后像这样映射对象:
init(with dictionary: [String: Any]?) {
guard let dictionary = dictionary else { return }
attribute = dictionary["attrName"] as? String
}
let customObjec = CustomStruct(dictionary: dictionary)
func parse(_ list: String) -> [String: String]? {
let scanner = Scanner(string: list)
guard scanner.scanString("[") else { return nil }
var result: [String: String] = [:]
let endOfPair: CharacterSet = [",", "]"]
repeat {
guard
let key = scanner.scanUpTo("="),
scanner.scanString("="),
let value = scanner.scanUpTo(endOfPair)
else {
return nil
}
result[key] = value
} while scanner.scanString(",")
guard scanner.scanString("]") else { return nil }
return result
}
我们已经有一些建议,首先在每个逗号处拆分字符串,然后在等号处拆分每个部分。这是相当容易编码和工作良好,但它不是非常有效,因为每个字符都必须检查多次。使用
Scanner
编写正确的解析器同样简单,但运行速度更快
基本上,扫描器可以检查给定字符串是否在当前位置,或者为您提供下一次出现分隔符之前的子字符串
这样,算法将具有以下步骤:
=
。这是关键=
、
或]
。这就是价值,
使用它并继续执行步骤3]
Scanner
API不是很友好。通过一个小的扩展,它更易于使用:
extension Scanner {
func scanString(_ string: String) -> Bool {
return scanString(string, into: nil)
}
func scanUpTo(_ delimiter: String) -> String? {
var result: NSString? = nil
guard scanUpTo(delimiter, into: &result) else { return nil }
return result as String?
}
func scanUpTo(_ characters: CharacterSet) -> String? {
var result: NSString? = nil
guard scanUpToCharacters(from: characters, into: &result) else { return nil }
return result as String?
}
}
使用此函数,我们可以编写如下解析函数:
init(with dictionary: [String: Any]?) {
guard let dictionary = dictionary else { return }
attribute = dictionary["attrName"] as? String
}
let customObjec = CustomStruct(dictionary: dictionary)
func parse(_ list: String) -> [String: String]? {
let scanner = Scanner(string: list)
guard scanner.scanString("[") else { return nil }
var result: [String: String] = [:]
let endOfPair: CharacterSet = [",", "]"]
repeat {
guard
let key = scanner.scanUpTo("="),
scanner.scanString("="),
let value = scanner.scanUpTo(endOfPair)
else {
return nil
}
result[key] = value
} while scanner.scanString(",")
guard scanner.scanString("]") else { return nil }
return result
}
糟糕的格式。责怪服务的所有者,让他发送一些标准化的东西,比如JSON。首先用
,
分隔字符串,然后在循环中用=
分隔每个项目,并将结果作为键/值插入[string:string]
字典。服务器是否提供任何其他输出格式?这不是一个流行的标准(json、yaml、csv、xml等),一旦有了它,剩下的就很简单了。回答得好。