Swift 包含数字的可解码蛇形钥匙 Issue
Swift decodable snake case key which include numbers Issue
我在解码 JSON 时遇到问题,它的键在蛇形盒中,包括数字。
我已经花了几天时间试图解决它,但我看不出有任何解决方案。尽管我非常需要它。我也不知道它为什么会失败。在这里的任何帮助表示赞赏。谢谢!
例如JSON:
{
"result": [
{
"symbol": "A",
"v_price_24h": "39652.50",
}
],
"time_now": "1645931312.379455"
}
会抛出错误:
keyNotFound(CodingKeys(stringValue: "vPrice24h", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "result", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: \"vPrice24h\", intValue: nil) (\"vPrice24h\").", underlyingError: nil))
我的模型 属性 是 vPrice24h
键 v_price_24h
在 JSON
这适用于所有情况,但当我的键中有数字时会失败
decoder.keyDecodingStrategy = .convertFromSnakeCase
与我定制的相同:
我花了几天时间试图弄清楚,但无法解决这个问题。
有谁知道怎么处理吗?
这里是游乐场:
import Foundation
var json = """
{
"result": [
{
"symbol": "A",
"v_price_24h": "39652.50",
}
],
"time_now": "1645931312.379455"
}
"""
struct CustomKey: CodingKey {
let stringValue: String
let intValue: Int?
init(stringValue: String) {
self.stringValue = stringValue
intValue = nil
}
init(intValue: Int) {
self.intValue = intValue
stringValue = String(intValue)
}
}
struct TopModel: Decodable {
let timeNow: String
let result: [InsideModel]
}
struct InsideModel: Decodable {
enum CodingKeys: String, CodingKey {
case symbol = "symbol"
case vPrice24h = "v_price_24h"
}
let symbol: String
let vPrice24h: String
}
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let decoder2 = JSONDecoder()
decoder2.keyDecodingStrategy = .custom { keys in
let last = keys.last!.stringValue
let snakePattern :String = "(\w{0,1})_"
var key = last.capitalized.replacingOccurrences(of: snakePattern, with: "", options: .regularExpression, range: nil)
if key.count > 1 {
key = key.prefix(1).lowercased() + key.dropFirst()
}
print(key, last)
return CustomKey(stringValue: key)
}
let decoder3 = JSONDecoder()
decoder3.keyDecodingStrategy = .useDefaultKeys
do {
_ = try decoder.decode(TopModel.self, from: json.data(using: .utf8)!)
} catch let thrownError {
print("", thrownError)
}
do {
_ = try decoder2.decode(TopModel.self, from: json.data(using: .utf8)!)
} catch let thrownError {
print("✅", thrownError)
}
do {
_ = try decoder3.decode(TopModel.self, from: json.data(using: .utf8)!)
} catch let thrownError {
print("", thrownError)
}
和结果
keyNotFound(CodingKeys(stringValue: "v_price_24h", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "result", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: \"v_price_24h\", intValue: nil) (\"v_price_24h\").", underlyingError: nil))
timeNow time_now
result result
symbol symbol
vPrice24H v_price_24h
✅ keyNotFound(CodingKeys(stringValue: "v_price_24h", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "result", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: \"v_price_24h\", intValue: nil) (\"v_price_24h\").", underlyingError: nil))
keyNotFound(CodingKeys(stringValue: "timeNow", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"timeNow\", intValue: nil) (\"timeNow\").", underlyingError: nil))
built-in 和您自定义的 snake case 策略都将 v_price_24h
转换为 vPrice24H
。因此,如果您将结构中的字段重命名为大写 H,则可以删除除策略之外的所有自定义项,并且它会起作用。
import Foundation
var json = """
{
"result": [
{
"symbol": "A",
"v_price_24h": "39652.50",
}
],
"time_now": "1645931312.379455"
}
"""
struct TopModel: Decodable {
let timeNow: String
let result: [InsideModel]
}
struct InsideModel: Decodable {
let symbol: String
let vPrice24H: String
}
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
do {
let model = try decoder.decode(TopModel.self, from: json.data(using: .utf8)!)
print("✅", model)
} catch let thrownError {
print("❌", thrownError)
}
最简单的形式 convertFromSnakeCase
let jsonString = """
{
"result": [
{
"symbol": "A",
"v_price_24h": "39652.50",
}
],
"time_now": "1645931312.379455"
}
"""
struct TopModel: Decodable {
let timeNow: String
let result: [InsideModel]
}
struct InsideModel: Decodable {
let symbol: String
let vPrice24h : String
}
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let result = try decoder.decode(TopModel.self, from: Data(jsonString.utf8))
print(result)
} catch {
print(error)
}
抛出的错误揭示了错误
keyNotFound(CodingKeys(stringValue: "vPrice24h", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "result", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: "vPrice24h", intValue: nil) ("vPrice24h"), with divergent representation vPrice24H, converted to v_price24h.", underlyingError: nil))
只需在数字
后用大写字母声明受影响的属性
let vPrice24H : String
如果你真的需要小写 h
应用这些 CodingKeys
struct InsideModel: Decodable {
private enum CodingKeys: String, CodingKey {
case symbol, vPrice24h = "vPrice24H"
}
let symbol: String
let vPrice24h : String
}
我在解码 JSON 时遇到问题,它的键在蛇形盒中,包括数字。 我已经花了几天时间试图解决它,但我看不出有任何解决方案。尽管我非常需要它。我也不知道它为什么会失败。在这里的任何帮助表示赞赏。谢谢!
例如JSON:
{
"result": [
{
"symbol": "A",
"v_price_24h": "39652.50",
}
],
"time_now": "1645931312.379455"
}
会抛出错误:
keyNotFound(CodingKeys(stringValue: "vPrice24h", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "result", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: \"vPrice24h\", intValue: nil) (\"vPrice24h\").", underlyingError: nil))
我的模型 属性 是 vPrice24h
键 v_price_24h
在 JSON
这适用于所有情况,但当我的键中有数字时会失败
decoder.keyDecodingStrategy = .convertFromSnakeCase
与我定制的相同: 我花了几天时间试图弄清楚,但无法解决这个问题。 有谁知道怎么处理吗?
这里是游乐场:
import Foundation
var json = """
{
"result": [
{
"symbol": "A",
"v_price_24h": "39652.50",
}
],
"time_now": "1645931312.379455"
}
"""
struct CustomKey: CodingKey {
let stringValue: String
let intValue: Int?
init(stringValue: String) {
self.stringValue = stringValue
intValue = nil
}
init(intValue: Int) {
self.intValue = intValue
stringValue = String(intValue)
}
}
struct TopModel: Decodable {
let timeNow: String
let result: [InsideModel]
}
struct InsideModel: Decodable {
enum CodingKeys: String, CodingKey {
case symbol = "symbol"
case vPrice24h = "v_price_24h"
}
let symbol: String
let vPrice24h: String
}
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let decoder2 = JSONDecoder()
decoder2.keyDecodingStrategy = .custom { keys in
let last = keys.last!.stringValue
let snakePattern :String = "(\w{0,1})_"
var key = last.capitalized.replacingOccurrences(of: snakePattern, with: "", options: .regularExpression, range: nil)
if key.count > 1 {
key = key.prefix(1).lowercased() + key.dropFirst()
}
print(key, last)
return CustomKey(stringValue: key)
}
let decoder3 = JSONDecoder()
decoder3.keyDecodingStrategy = .useDefaultKeys
do {
_ = try decoder.decode(TopModel.self, from: json.data(using: .utf8)!)
} catch let thrownError {
print("", thrownError)
}
do {
_ = try decoder2.decode(TopModel.self, from: json.data(using: .utf8)!)
} catch let thrownError {
print("✅", thrownError)
}
do {
_ = try decoder3.decode(TopModel.self, from: json.data(using: .utf8)!)
} catch let thrownError {
print("", thrownError)
}
和结果
keyNotFound(CodingKeys(stringValue: "v_price_24h", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "result", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: \"v_price_24h\", intValue: nil) (\"v_price_24h\").", underlyingError: nil))
timeNow time_now
result result
symbol symbol
vPrice24H v_price_24h
✅ keyNotFound(CodingKeys(stringValue: "v_price_24h", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "result", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: \"v_price_24h\", intValue: nil) (\"v_price_24h\").", underlyingError: nil))
keyNotFound(CodingKeys(stringValue: "timeNow", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"timeNow\", intValue: nil) (\"timeNow\").", underlyingError: nil))
built-in 和您自定义的 snake case 策略都将 v_price_24h
转换为 vPrice24H
。因此,如果您将结构中的字段重命名为大写 H,则可以删除除策略之外的所有自定义项,并且它会起作用。
import Foundation
var json = """
{
"result": [
{
"symbol": "A",
"v_price_24h": "39652.50",
}
],
"time_now": "1645931312.379455"
}
"""
struct TopModel: Decodable {
let timeNow: String
let result: [InsideModel]
}
struct InsideModel: Decodable {
let symbol: String
let vPrice24H: String
}
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
do {
let model = try decoder.decode(TopModel.self, from: json.data(using: .utf8)!)
print("✅", model)
} catch let thrownError {
print("❌", thrownError)
}
最简单的形式 convertFromSnakeCase
let jsonString = """
{
"result": [
{
"symbol": "A",
"v_price_24h": "39652.50",
}
],
"time_now": "1645931312.379455"
}
"""
struct TopModel: Decodable {
let timeNow: String
let result: [InsideModel]
}
struct InsideModel: Decodable {
let symbol: String
let vPrice24h : String
}
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let result = try decoder.decode(TopModel.self, from: Data(jsonString.utf8))
print(result)
} catch {
print(error)
}
抛出的错误揭示了错误
keyNotFound(CodingKeys(stringValue: "vPrice24h", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "result", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: "vPrice24h", intValue: nil) ("vPrice24h"), with divergent representation vPrice24H, converted to v_price24h.", underlyingError: nil))
只需在数字
后用大写字母声明受影响的属性let vPrice24H : String
如果你真的需要小写 h
应用这些 CodingKeys
struct InsideModel: Decodable {
private enum CodingKeys: String, CodingKey {
case symbol, vPrice24h = "vPrice24H"
}
let symbol: String
let vPrice24h : String
}