【问题标题】:Swift JSON Decodable \u0000Swift JSON 可解码 \u0000
【发布时间】:2020-11-28 06:25:40
【问题描述】:

问题

我目前正在从我无权访问的服务器获取 JSON。我有时得到的 JSON 会将这个字符 \u0000 放在字符串的末尾。结果我的解码失败了,因为这个字符失败了。

我正在尝试在 Playground 中调试它,但我不断收到此错误。

Expected hexadecimal code in braces after unicode escape

这里有一些示例代码供您试用。

import UIKit
import Foundation

struct GroceryProduct: Codable {
    var name: String
}

let json = """
{
    "name": "Durian \u0000"
}
""".data(using: .utf8)!

let decoder = JSONDecoder()
let product = try decoder.decode(GroceryProduct.self, from: json)

print(product.name)

问题

你如何处理来自 JSON 的\u0000?我一直在查看 Apple 文档中的 DataDecodingStrategy,但我什至无法测试任何东西,因为 Playground 甚至无法运行。

任何方向或建议将不胜感激。


更新

这里有更多设置代码可以在您的 Playground 或真实应用中试用。

JSON 测试.json

{
    "name": "Durian \u0000"
}

代码

extension Bundle {
    func decode<T: Decodable>(_ type: T.Type, from file: String, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .deferredToDate, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) -> T {
        
        guard let url = self.url(forResource: file, withExtension: nil) else {
            fatalError("Failed to locate \(file) in bundle.")
        }

        guard let data = try? Data(contentsOf: url) else {
            fatalError("Failed to load \(file) from bundle.")
        }
                
        let decoder = JSONDecoder()
        decoder.dateDecodingStrategy    = .deferredToDate
        decoder.keyDecodingStrategy     = .useDefaultKeys

        do {
            return try decoder.decode(T.self, from: data)
        } catch DecodingError.keyNotFound(let key, let context) {
            fatalError("Failed to decode \(file) from bundle due to missing key '\(key.stringValue)' not found – \(context.debugDescription)")
        } catch DecodingError.typeMismatch(_, let context) {
            fatalError("Failed to decode \(file) from bundle due to type mismatch – \(context.debugDescription)")
        } catch DecodingError.valueNotFound(let type, let context) {
            fatalError("Failed to decode \(file) from bundle due to missing \(type) value – \(context.debugDescription)")
        } catch DecodingError.dataCorrupted(_) {
            fatalError("Failed to decode \(file) from bundle because it appears to be invalid JSON")
        } catch {
            fatalError("Failed to decode \(file) from bundle: \(error.localizedDescription)")
        }
    }
}


struct GroceryProduct: Codable {
    var name: String
}

// Try running this and it won't work
let results = Bundle.main.decode(GroceryProduct.self, from: "test.json")


print(results.name)

【问题讨论】:

  • 我用 Xcode 11.6 尝试了你的 Playground 代码(你的 JSON 文件应该是 test.json,而不是 Text.json)并且无法重现错误 Expected hexadecimal code in braces after unicode escape。我认为这只是字符串文字的问题,而不是解码 JSON 的问题。一般\u0000在JSON字符串中有效,代表U+0000 NUL。如果那是无关的并且不应该存在,那是 API 的错误,您最好将错误报告发送给服务器端工程师。
  • 我希望我可以为服务器端工程师创建一个错误报告,但在我的情况下我不能

标签: ios json swift unicode jsondecoder


【解决方案1】:

您需要先转义 \u0000 字符 - 这可以在 解码之前完成:

guard let data = try? Data(contentsOf: url) else {
    fatalError("Failed to load \(file) from bundle.")
}

let escaped = Data(String(data: data, encoding: .utf8)!.replacingOccurrences(of: "\0", with: "").utf8)
...
return try decoder.decode(T.self, from: escaped)

注意:仅为简单起见强制展开。


在 Playground 中,您可以使用额外的 \ 来逃避它(使其工作):

let json = """
{
    "name": "Durian \\u0000"
}
""".data(using: .utf8)!

或将其替换为\0(使其失败 - 就像在解码期间一样):

let json = """
{
    "name": "Durian \0"
}
""".data(using: .utf8)!

【讨论】:

  • 您的解决方案的问题是我得到的 JSON 来自另一台服务器。所以我正在使用游乐场来尝试调试我的问题。在现实生活中,我无法访问 JSON 服务器,也无法要求他们添加反斜杠。
  • 我在原始问题中添加了更多详细信息,以使用本地 json 文件进行测试。我不知道我会把String(data: json, encoding: .utf8)!.replacingOccurrences(of: "\0", with: "").data(using: .utf8)!
  • 谢谢。这使我走上了正确的道路。我很感激。
  • utf8 转数据时无需强制解包(虽然安全,但绝不会失败)。 Data("string".utf8)
猜你喜欢
  • 1970-01-01
  • 2019-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-28
  • 1970-01-01
相关资源
最近更新 更多