将字符串与CSV文件分开

时间:2017-04-02 00:07:28

标签: swift string csv dictionary

目前我要让用户导入从.addmleader(pointsarray, leaderlineindex as long)CSV-file创建的Excel。工作表有多个字段,我可以毫无问题地导入它们。

但是,其中一个字段如下所示:

Numbers

我应该如何将这个字段分成如下字典:

"[Title1: (100: S11), (100: S12), (100: 10), (100: 2), (100: 3)], [Title2: (300: 50), (300: 90), (300: 100a), (300: D), (300: E)], [Title3: (500: 2), (500: 112), (500: 6), (500: 110), (500: 113)]"

此字段由用户自己创建,这似乎有点太复杂,容易出错。或许更好的问题是如何更好地格式化这个而不是将这个字段分成我想要的字典?

也许简化版本:

//[String: [[Int: String]]]

[
    "Title1": [[100: "S11"], [100: "S12"], [100:   "10"], [100:   "2"], [100:   "3"]],
    "Title2": [[300:  "50"], [300:  "90"], [300: "100a"], [300:   "D"], [300:   "E"]],
    "Title3": [[500:   "2"], [500: "112"], [500:    "6"], [500: "110"], [500: "113"]]
]

关于这个领域的一些解释:

标题:可以是任何东西,它是嵌套字典的标题

嵌套字典中的键可以是//[String: [Int: [String]]] [ "Title1": [100: ["S11", "S12", "10", "2", "3"]], "Title2": [300: ["50", "90", "100a", "D", "E"]], "Title3": [500: ["2", "112", "6", "110", "113"]] ]

嵌套字典中的值是100, 200, 300, 400, 500 or 600,它与它们在此嵌套字典中键入时形成唯一键。

这意味着:

String
100: "S11" and 200: "S11" // valid
100: "S11" and 100: "S11" // not valid

此代码生成我想要的结果,但它看起来非常难看,而且它过分依赖于值的位置(而不是检查值)。

有关如何使用更简单,更优雅的方式做到这一点的任何建议吗?

2 个答案:

答案 0 :(得分:0)

以下代码应该根据需要将您提供的数据解析为字典:

    let data = "[Title1: (100: S11), (100: S12), (100: 10), (100: 2), (100: 3)], [Title2: (300: 50), (300: 90), (300: 100a), (300: D), (300: E)], [Title3: (500: 2), (500: 112), (500: 6), (500: 110), (500: 113)]"

    let arr1 = data.components(separatedBy:"],")
    var dic = [String:[[String:Any]]]()
    for row1 in arr1 {
        let arr2 = row1.components(separatedBy:",")
        var key = ""
        for row2 in arr2 {
            var txt = row2.replacingOccurrences(of:" ", with:"")
            if txt.hasPrefix("[Title") {
                // First row
                txt = txt.replacingOccurrences(of:"[", with:"")
                let arr3 = txt.components(separatedBy:":")
                key = arr3[0]
                let key1 = arr3[1].replacingOccurrences(of:"(", with:"")
                let val1 = arr3[2].replacingOccurrences(of:")", with:"").replacingOccurrences(of:" ", with:"")
                dic[key] = [[key1:val1]]
            } else {
                let arr3 = row2.components(separatedBy:":")
                let key1 = arr3[0].replacingOccurrences(of:"(", with:"").replacingOccurrences(of:" ", with:"")
                let val1 = arr3[1].replacingOccurrences(of:")", with:"").replacingOccurrences(of:"]", with:"").replacingOccurrences(of:" ", with:"")
                dic[key]?.append([key1:val1])
            }
        }
    }
    print(dic)

以上回答了您的第一个问题,如何解析您指定的字典中提供的数据。第二个问题有点复杂,因为我不太了解数据以提供有用的答案。但是现在也许这是不必要的,因为数据可以根据需要拆分成字典? :)

答案 1 :(得分:0)

我假设你确定了第一种出口格式,即

[Title1: (100: S11), (100: S12), (100: 10), (100: 2), (100: 3)], [Title2: (300: 50), (300: 90), (300: 100a), (300: D), (300: E)], [Title3: (500: 2), (500: 112), (500: 6), (500: 110), (500: 113)]

您可以使用RegEx来解析该字符串。以下答案不能处理错误。如果标题包含分号(:

,它也将无效
extension String {
    subscript(_ range: NSRange) -> String {
        let startIndex = self.utf16.index(self.utf16.startIndex, offsetBy: range.location)
        let endIndex = self.utf16.index(startIndex, offsetBy: range.length)

        return String(describing: self.utf16[startIndex..<endIndex])
    }
}

let str = "[Title1: (100: S11), (100: S12), (100: 10), (100: 2), (100: 3)], [Title2: (300: 50), (300: 90), (300: 100a), (300: D), (300: E)], [Title3: (500: 2), (500: 112), (500: 6), (500: 110), (500: 113)]"
let regex1 = try! NSRegularExpression(pattern: "\\[(.+?): (.+?)\\]", options: [])
let regex2 = try! NSRegularExpression(pattern: "\\((\\d+?): (.+?)\\)", options: [])

var result = [String: [Int: [String]]]()

regex1.enumerateMatches(in: str, options: [], range: NSMakeRange(0, str.utf16.count)) { match1, _, _ in
    guard let match1 = match1 else { return }

    let title = str[match1.rangeAt(1)]
    let categoriesStr = str[match1.rangeAt(2)]
    var categories = [Int: [String]]()

    regex2.enumerateMatches(in: categoriesStr, options: [], range: NSMakeRange(0, categoriesStr.utf16.count)) { match2, _, _ in
        guard let match2 = match2 else { return }

        let number = Int(categoriesStr[match2.rangeAt(1)])!
        let identifier = categoriesStr[match2.rangeAt(2)]

        if categories[number] == nil {
            categories[number] = [String]()
        }
        categories[number]!.append(identifier)
    }

    result[title] = categories
}

print(result)