You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Swift/iOS中导入解析Pandas导出的JSON文件?

解决Swift/iOS解析Pandas导出的JSON Lines文件问题

看起来你遇到的问题大概率是JSON格式不匹配导致的——你用Pandas的lines=True导出的是**JSON Lines(每行一个独立JSON对象)**格式,但Swift的Codable默认期望的是标准JSON数组(外层用[]包裹,对象间用逗号分隔),直接用SwiftyJSON解析整个文件也会因为格式不合法报错。

先确认下你的sample.json内容大概是这种结构:

{"url":"xxx", "name":"xxx", ...}
{"url":"yyy", "name":"yyy", ...}

而非标准的数组格式:

[{"url":"xxx", ...}, {"url":"yyy", ...}]

下面给你两种可行的解决思路:

方案一:修改Pandas导出格式(最简单直接)

如果可以调整导出代码,去掉lines=True参数,让Pandas直接导出标准JSON数组:

shops.to_json("sample.json", orient='records', force_ascii=False)

这样导出的文件就是合法的JSON结构,Swift里直接用Codable解析数组即可:

struct Restaurant: Codable {
    let url: String
    let name: String
    let address: String
    let pref: String
    let zip: String
    let tel: String
    let latitude: Float
    let longitude: Float
    let price: String
    // 补充你的其他属性...
}

// 解析示例代码
if let url = Bundle.main.url(forResource: "sample", withExtension: "json"),
   let data = try? Data(contentsOf: url),
   let restaurants = try? JSONDecoder().decode([Restaurant].self, from: data) {
    print("成功解析 \(restaurants.count) 条餐厅数据")
}

方案二:在Swift中适配JSON Lines格式

如果没办法修改导出的JSON文件,那就需要手动读取文件的每一行,逐个解析JSON对象:

// 读取文件内容并按行分割
guard let url = Bundle.main.url(forResource: "sample", withExtension: "json"),
      let content = try? String(contentsOf: url) else {
    print("无法读取JSON文件")
    return
}

// 过滤空行,避免解析出错
let lines = content.components(separatedBy: .newlines).filter { !$0.isEmpty }

let decoder = JSONDecoder()
var restaurants = [Restaurant]()

for line in lines {
    guard let data = line.data(using: .utf8) else {
        print("行内容转Data失败: \(line)")
        continue
    }
    do {
        let restaurant = try decoder.decode(Restaurant.self, from: data)
        restaurants.append(restaurant)
    } catch {
        print("解析行失败: \(error.localizedDescription),行内容: \(line)")
    }
}

print("最终解析得到 \(restaurants.count) 条数据")

如果用SwiftyJSON处理,逻辑也是类似的逐行解析:

import SwiftyJSON

guard let url = Bundle.main.url(forResource: "sample", withExtension: "json"),
      let content = try? String(contentsOf: url) else {
    return
}

let lines = content.components(separatedBy: .newlines).filter { !$0.isEmpty }
var restaurants = [Restaurant]()

for line in lines {
    guard let data = line.data(using: .utf8),
          let json = try? JSON(data: data) else {
        continue
    }
    // 手动映射到Restaurant对象
    let restaurant = Restaurant(
        url: json["url"].stringValue,
        name: json["name"].stringValue,
        address: json["address"].stringValue,
        pref: json["pref"].stringValue,
        zip: json["zip"].stringValue,
        tel: json["tel"].stringValue,
        latitude: json["latitude"].floatValue,
        longitude: json["longitude"].floatValue,
        price: json["price"].stringValue
        // 补充其他属性...
    )
    restaurants.append(restaurant)
}

最后提醒几个细节:

  • 确认Pandas导出的latitudelongitude是数值类型,而非字符串,否则Swift用Float解析会失败
  • 如果有可选字段,记得在Restaurant结构体中把对应属性设为可选类型(比如let price: String?
  • 解析时保留错误捕获逻辑,能帮你快速定位具体哪一行或哪个字段出了问题

内容的提问来源于stack exchange,提问作者YOSUKE

火山引擎 最新活动