在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等),一旦有了它,剩下的就很简单了。回答得好。