在Swift中将String解析为一个对象

时间:2018-11-21 17:35:28

标签: 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
]

如何以最简单的方式将其很好地转换为格式正确的快速对象?

这是我的尝试,仅能给我带来Sprint价值

if sprintJiraCustomField.count > 0 {
                         let stringOutput = sprintJiraCustomField.first?.stringValue // convert output to String
                        let name = stringOutput?.components(separatedBy: "name=") // get name section from string
                        let nameFieldRaw = name![1].components(separatedBy: ",") // split out to the comma
                        let nameValue = nameFieldRaw.first!
                        sprintDetail = nameValue// show name field
                        }

3 个答案:

答案 0 :(得分:1)

不知道您想要什么格式,但是下面的代码将生成一个元组(键,值)数组,但是所有值都是字符串,因此我猜想之后需要再次转换

let items = stringOutput.components(separatedBy: ",").compactMap( {pair -> (String, String) in
    let keyValue = pair.components(separatedBy: "=")
    return (keyValue[0], keyValue[1])
})

答案 1 :(得分:0)

这是减少工作:

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)

答案 2 :(得分:0)

我们已经有一些建议,首先在每个逗号处分割字符串,然后在等号处分割每个部分。这很容易编写代码,并且效果很好,但是效率不高,因为每个字符必须多次检查。使用Scanner编写适当的解析器同样容易,但是运行起来会更快。

基本上,扫描程序可以检查给定的字符串是否在当前位置,或者为您提供子字符串,直到下一次出现分隔符为止。

该算法将具有以下步骤:

  1. 使用输入字符串创建扫描仪
  2. 检查左括号,否则失败
  3. 最多扫描第一个=。这是关键
  4. 使用=
  5. 最多扫描第一个,]。这就是价值
  6. 存储键/值对
  7. 如果有,,请消耗掉它并继续执行步骤3
  8. 使用最终的]

可悲的是,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?
    }
}

有了这个,我们可以编写如下的解析函数:

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
}