解码 JSON (Swift) 时将单个字符串拆分为多个部分

Posted

技术标签:

【中文标题】解码 JSON (Swift) 时将单个字符串拆分为多个部分【英文标题】:Split a single string into several portions when decoding a JSON (Swift) 【发布时间】:2021-08-27 10:59:22 【问题描述】:

我有一个 JSON 文件,其中包含大约 3000 个以下格式(10 位数字)的唯一 ID 代码:

1012111000

我目前正在将其导入到以下格式的简单结构中:

struct Codes: Codable, Identifiable 
  let id: String

使用以下扩展:

extension Bundle 
  func decode<T: Codable>( file: String) -> T 
    guard let url = self.url(forResource: file, withExtension: nil) else 
      fatalError("Failred to locate \(file) in bundle")
    
    guard let data = try? Data(contentsOf: url) else 
      fatalError("Failred to load \(file) from bundle")
    
    let decoder = JSONDecoder()
    guard let loaded = try? decoder.decode(T.self, from: data) else 
      fatalError("Failed to decode \(file) from bundle")
    
    return loaded
  

然后打电话

let code: [Codes] = Bundle.main.decode(file: "codes.json")

这按预期工作,数据在 Swift 中可用。 但是。 id 代码实际上由 4 个单独的代码组成。前 3 个字符是一个 3 位代码,第 4 个字符是另一个个位代码,第 5 和第 6 个字符构成第三个 2 位代码,最后四个字符构成最终的 4 位代码。因此,我想改为按如下方式导入结构:请注意,id4 是唯一的,但 id1、id2 和 id3 会有重复。

struct Codes: Codable, Identifiable 
  let id1: String    // 1st-3rd character (3 digits)
  let id2: String    // 4th character (1 digit)
  let id3: String    // 5th-6th character (2 digits)
  let id4: String    // 7th-10th characters (4 digits)

任何关于如何以一种简洁的方式实现这一点的建议将不胜感激。我知道有很多解析字符串的方法,但我不确定如何最好地在循环中完成它。我还应该注意,解码器是通用的,因为它需要导入许多其他(更简单的)JSON,并且需要保留此功能。

最好, sy

【问题讨论】:

快速代码建议:将id设为private、id1id2id3 & id4lazy,然后从id创建。由于您的代码已经可以工作(我假设),它应该是最好的方法。 【参考方案1】:

使“代码”与您已有的和组件 ID 兼容, 试试这种方法,或类似的方法:

struct Codes: Codable, Identifiable 
    let id: String
    
    func id1() -> String  string(from: 0, to: 3) 
    func id2() -> String  string(from: 3, to: 4) 
    func id3() -> String  string(from: 5, to: 7) 
    func id4() -> String  string(from: 6, to: 10) 

   // or using lazy var
   // lazy var id1: String =  string(from: 0, to: 3) ()
   // lazy var id2: String =  string(from: 3, to: 4) ()
   // lazy var id3: String =  string(from: 5, to: 7) ()
   // lazy var id4: String =  string(from: 6, to: 10) ()
    
    private func string(from: Int, to: Int) -> String 
        let start = id.index(id.startIndex, offsetBy: from)
        let end = id.index(id.startIndex, offsetBy: to)
        return String(id[start..<end])
    

注意,使用lazy var时需要声明:

var code = Codes(id: "1012111000")

不是

let code = Codes(id: "1012111000")

与函数一样。

【讨论】:

这会不必要地从 startIndex 偏移所有索引。将to 更改为length 并从已知的开始偏移长度或简单地减去from 并偏移结果 这很奏效 - 非常感谢! lazy var 不是更好的选择吗?他们不会每次都重新计算吗?很小,但在打电话给他们时会避免()吗? 足够公平的评论,我会用lazy var选项。 您好 - 我尝试了 lazy var 方法而不是 func。我还用var codes: [Codes] 而不是let 替换了初始解码器调用,但这对我不起作用-它错误为“不能在不可变值上使用变异getter:'codes'是'let'常量

以上是关于解码 JSON (Swift) 时将单个字符串拆分为多个部分的主要内容,如果未能解决你的问题,请参考以下文章

Swift解码字符串JSON失败

Swift 4 - Json 解码器

Elm:将具有单个元素的 JSON 数组解码为字符串

Swift Codable - 如何编码和解码字符串化的 JSON 值?

Swift 4 Xcode 使用 JSON 解码的问题

当您不知道 Swift 中的项目类型时,如何解码嵌套的 JSON 数据? [复制]