序列化包含转义(反斜杠和双引号)的 JSON 字符串 Swift 返回格式错误的对象

Posted

技术标签:

【中文标题】序列化包含转义(反斜杠和双引号)的 JSON 字符串 Swift 返回格式错误的对象【英文标题】:Serialize JSON string that contains escaped (backslash and double quote) Swift return Badly formed object 【发布时间】:2018-10-26 04:36:56 【问题描述】:

我有来自后端的响应字符串,如下所示:


    "status": "success",
    "data": "\"name\":\"asd\",\"address\":\"Street 1st\""

我认为问题是因为数据字符串中的双引号(“)。当我删除双引号时,序列化成功。但是响应来自后端,我必须处理它。

谁能解决这个问题?

谢谢。

这里是操场代码。

import Foundation
var jsonStr = """

"status": "success",
"data": "\"name\":\"asd\",\"address\":\"Street 1st\""

"""
let data = jsonStr.data(using: .utf8)
if let d = data 
    do 
        let o = try JSONSerialization.jsonObject(with: d)
        print(o)
     catch let e 
        print(e)
    
 else 
    print("DATA conversion ERROR")

【问题讨论】:

【参考方案1】:

首先,如果您将 JSON 包装在 Swift 4 的文字字符串语法中,则必须转义反斜杠。

let jsonStr = """

"status": "success",
"data": "\\"name\\":\\"asd\\",\\"address\\":\\"Street 1st\\""

"""

你得到了嵌套的 JSON。键 data 的值是另一个 JSON 字符串,必须单独反序列化

let jsonData = Data(jsonStr.utf8)

do 
    if let object = try JSONSerialization.jsonObject(with: jsonData) as? [String:String] 
        print(object)
        if let dataString = object["data"] as? String 
            let dataStringData = Data(dataString.utf8)
            let dataObject = try JSONSerialization.jsonObject(with: dataStringData) as? [String:String]
            print(dataObject)
        
    
 catch 
    print(error)

或者 – 付出更多的努力,但 – 对 (De)Codable 协议更满意

struct Response : Decodable 

    private enum CodingKeys : String, CodingKey  case status, data 

    let status : String
    let person : Person

    init(from decoder: Decoder) throws 
        let container = try decoder.container(keyedBy: CodingKeys.self)
        status = try container.decode(String.self, forKey: .status)
        let dataString = try container.decode(String.self, forKey: .data)
        person = try JSONDecoder().decode(Person.self, from: Data(dataString.utf8))
    


struct Person : Decodable 
    let name, address : String


let jsonStr = """

"status": "success",
"data": "\\"name\\":\\"asd\\",\\"address\\":\\"Street 1st\\""

"""
let jsonData = Data(jsonStr.utf8)

do 
    let result = try JSONDecoder().decode(Response.self, from: jsonData)
    print(result)
 catch 
    print(error)

【讨论】:

如何更改 jsonStr 的值?因为我从 API 获得了 jsonStr(无法更改)。 对不起,我不明白。 数据必须是"\"name\":\"asd\",\"address\":\"Street 1st\"",不能更改。或者你知道如何将数据改为双反斜杠吗? 需要第二个反斜杠才能按字面意思使用它,例如在 Playground 中。服务器只发送 一个 反斜杠。 哦,我知道了,我先试试。谢谢@vadian【参考方案2】:

你的代码有错误,因为你用“”“json”“”这样的代码编写它,

还有 dataString 不是字典,所以你需要转换为数据然后 JSONSerialization 再次

检查代码我将您的响应添加到 Json 文件中并解析它,并正常工作

所以只需将它写在名为 data.json 的 json 文件中


    "status": "success",
    "data": "\"name\":\"asd\",\"address\":\"Street 1st\""

并使用它:

            guard let  jsonFile =  Bundle.main.path(forResource: "data", ofType: "json") else  return

            guard  let data = try? Data(contentsOf: URL(fileURLWithPath: jsonFile), options: .mappedIfSafe) else return

            if let response  = try? JSONSerialization.jsonObject(with: data, options: .mutableLeaves) 
                print(response)
                if let dataInDictionary = response as? [String:Any] , let addresData = dataInDictionary["data"] as? String 

                    if let jsonData = addresData.data(using: .utf8),
                        let dictionary = try? JSONSerialization.jsonObject(with: jsonData, options: .mutableLeaves) as? [String:Any]
                        print(dictionary)
                    
                
            

【讨论】:

【参考方案3】:

这是另一个基于答案@vadian的例子

Swift 4 - 使用 Codable

这是我收到的 json:


    "error_code": 0,
    "result": 
        "responseData": "\"emeter\":\"get_realtime\":\"voltage_mv\":237846,\"current_ma\":81,\"power_mw\":7428,\"total_wh\":1920,\"err_code\":0"
    
 

带有反斜杠的 JSON 部分等于:


    "emeter": 
        "get_realtime": 
            "voltage_mv": 237846,
            "current_ma": 81,
            "power_mw": 7428,
            "total_wh":19201,
            "err_code":0
        
    

这是我使用的代码:

import Foundation

class RealtimeEnergy: Codable 
    let errorCode: Int
    let result: ResultRealtimeEnergy?
    let msg: String?

    enum CodingKeys: String, CodingKey 
        case errorCode = "error_code"
        case result, msg
    

    init(errorCode: Int, result: ResultRealtimeEnergy?, msg: String?) 
        self.errorCode = errorCode
        self.result = result
        self.msg = msg
    


class ResultRealtimeEnergy: Codable 

    let responseData: String
    var emeter: Emeter

    enum CodingKeys: String, CodingKey 
        case responseData
    

    required init(from decoder: Decoder) throws 

        let container = try decoder.container(keyedBy: CodingKeys.self)
        responseData = try container.decode(String.self, forKey: .responseData)
        let dataString = try container.decode(String.self, forKey: .responseData)
        emeter = try JSONDecoder().decode(Emeter.self, from: Data(dataString.utf8))
    




class Emeter: Codable 
    let emeter: EmeterClass

    init(emeter: EmeterClass) 
        self.emeter = emeter
    


class EmeterClass: Codable 
    let getRealtime: GetRealtime

    enum CodingKeys: String, CodingKey 
        case getRealtime = "get_realtime"
    

    init(getRealtime: GetRealtime) 
        self.getRealtime = getRealtime
    


class GetRealtime: Codable 
    let voltageMv, currentMa, powerMw, totalWh: Int
    let errCode: Int

    enum CodingKeys: String, CodingKey 
        case voltageMv = "voltage_mv"
        case currentMa = "current_ma"
        case powerMw = "power_mw"
        case totalWh = "total_wh"
        case errCode = "err_code"
    

    init(voltageMv: Int, currentMa: Int, powerMw: Int, totalWh: Int, errCode: Int) 
        self.voltageMv = voltageMv
        self.currentMa = currentMa
        self.powerMw = powerMw
        self.totalWh = totalWh
        self.errCode = errCode
    

【讨论】:

以上是关于序列化包含转义(反斜杠和双引号)的 JSON 字符串 Swift 返回格式错误的对象的主要内容,如果未能解决你的问题,请参考以下文章

json特殊字符都有哪些

js单引号和双引号的转义问题

sql注入逃逸双引号转义

引号嵌套

linux命令学习-引用符号(反斜杠,单引号'',双引号"")

每日linux命令学习-引用符号(反斜杠,单引号'',双引号"")