Swift JSON 可解码 \u0000

Swift JSON Decodable \u0000

问题

我目前正在从我无权访问的服务器获取 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 test.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)

您需要先转义 \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: "[=10=]", with: "").utf8)
...
return try decoder.decode(T.self, from: escaped)

注意:force-unwrapping 仅为了简单起见。


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

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

或用 [=15=] 替换它(使它失败 - 在解码期间表现得像):

let json = """
{
    "name": "Durian [=12=]"
}
""".data(using: .utf8)!