字符串到字典(从QRCode字符串获取值)

时间:2017-01-26 21:36:39

标签: ios swift

我正在尝试生成QRCode,然后将其读入。我的问题是我不知道如何从QRCode字符串中获取值。

我的QRCode中的字符串如下:["firstName": "John", "lastName": "Bush"]

我实现了这样:

let dict = ["firstName":firstName, "lastName": lastName]
dict.description

现在我想从中获取价值,我该怎么做?我试图将字符串转换回字典但不能这样做。

2 个答案:

答案 0 :(得分:2)

如果您真的对解析此结果感兴趣,那么当然有办法实现。除非您的来源有一致的格式,否则它永远不会一直成功。如果它是一致的,你当然可以做这样的事情:

//get the string representation of our dictionary
let code = "[\"firstName\": \"firstName\", \"lastName\": \"lastName\"]"
//remove the brackets
let bracketless = String(code.characters.dropFirst().dropLast())
//get rid of our quotes
let quoteless = bracketless.replacingOccurrences(of: "\"", with: "")
//split our dictionary by key/value pairs
let pairs = quoteless.components(separatedBy: ", ")
//now split our key/value pairs into each key and value component respectively
let values: [[String]] = pairs.map { $0.components(separatedBy: ": ") }

//create ourself a dictionary to populate with our parsed data
var dict: [String:Any] = [:]
values.forEach { dict[$0[0]] = $0[1] } //populate the dictionary
print(dict) // ["lastName": "lastName", "firstName": "firstName"]

使用标准化格式(例如JSON)总是更好。也许在你的情况下,这不是一个选择。我仍然想知道为什么你会在这种情况下......

答案 1 :(得分:1)

这是相当棘手的,description的结果并不真正意味着用作交换格式。最好的办法是使用不同的格式来生成QR码。但是我们假设现在为时已晚。

要获取数据,您需要编写解析器,因为系统不提供描述格式的解析器。听起来很难,但事实并非如此。您可以考虑使用String方法components(separatedBy:),但这会变得非常低效。基金会Scanner课程是一个更好的工具。

要编写的最简单的解析器是“递归下降”解析器。这意味着您要识别的每个部件都要编写一个函数来调用子部件的这些函数。所以让我们看看我们在这里有什么:

  • 外层是字典。这以字符串“[”开头,然后我们将键/值对分隔为“,”,最后是另一个“]”。 (也可能是空字典的情况,只是“[]”
  • 然后我们有一对。这是引号内的字符串,后跟“:”和另一个引用的字符串。
  • 最后一部分是引用的字符串。我们有引用",以及下一个引用的任何其他字符。

所以在伪代码中,这看起来像这样:

func dictionary() {
   expect("[")
   if !read("]") {
      repeat {
          pair()
      } while read(",")
   }
   expect("]")
}

func pair() {
    quotedString()
    expect(":")
    quotedString()
}

func quotedString() {
   expect("\"")
   readUpTo("\"")
   expect("\"")
}

此处expectreadreadUpTo是Scanner类提供的方法的占位符。如果我们提供这些,那基本上就是完整的解析器。但是像这样它不是很有用,因为它只是忽略了数据。所以我们需要扩展我们的解析器,以便它实际返回找到的数据。

最终结果可能如下所示:

let scanner = Scanner(string: string)

func dictionary() -> [String: String]? {
    guard scanner.scanString("[", into: nil) else { return nil }

    var result: [String: String] = [:]

    if !scanner.scanString("]", into: nil) {
        repeat {
            guard let (key, value) = pair() else { return nil }
            result[key] = value
        } while scanner.scanString(",", into: nil)
    }

    guard scanner.scanString("]", into: nil) else { return nil }

    return result
}

func pair() -> (String, String)? {
    guard let key = quotedString(),
        scanner.scanString(":", into: nil),
        let value = quotedString()
    else {
            return nil
    }

    return (key, value)
}

func quotedString() -> String? {
    guard scanner.scanString("\"", into: nil) else { return nil }

    var result: NSString? = nil
    guard scanner.scanUpTo("\"", into: &result), let string = result as? String else { return nil }

    guard scanner.scanString("\"", into: nil) else { return nil }

    return string
}

使用字符串拆分的hacky解决方案的一些代码,但不是真的很复杂,而且更灵活。如果字符串本身包含“,”或“:”,我们将不会有任何问题。性能也会更好,因为在这里我们只看一次每个角色。另一个解决方案必须三次查看每个角色。

它仍有一个问题:如果您的任何字符串包含双引号字符,则此解析器将失败。字典的description属性将以反斜杠引用的形式输出\" - 这必须在quotedString中处理。