使用 Codable 序列化为 JSON 时 Swift 字符串转义

问题描述 投票:0回答:5

我正在尝试按如下方式序列化我的对象:

import Foundation

struct User: Codable {
    let username: String
    let profileURL: String
}

let user = User(username: "John", profileURL: "http://google.com")

let json = try? JSONEncoder().encode(user)

if let data = json, let str = String(data: data, encoding: .utf8) {
    print(str)
}

但是在 macOS 上我得到以下信息:

{"profileURL":"http:\/\/google.com","username":"John"}

(注意转义的“/”字符)。

在 Linux 机器上我得到:

{"username":"John","profileURL":"http://google.com"}

如何让 JSONEncoder 返回未转义的内容?

我需要 JSON 中的字符串严格不转义。

ios json swift macos codable
5个回答
51
投票

您可以使用 json 解码器的

.withoutEscapingSlashes
选项来避免转义斜杠

let user = User(username: "John", profileURL: "http://google.com")

let jsonEncoder = JSONEncoder()
jsonEncoder.outputFormatting = .withoutEscapingSlashes
let json = try? jsonEncoder.encode(user)

if let data = json, let str = String(data: data, encoding: .utf8) {
    print(str)
}

控制台 O/P

{"profileURL":"http://google.com","用户名":"约翰"}


注意: 正如 Martin R 在评论中提到的那样,

\/
是一个有效的 JSON 转义序列。


22
投票

我最终使用了

replacingOccurrences(of:with:)
,这可能不是最好的解决方案,但它解决了问题:

import Foundation

struct User: Codable {
    let username: String
    let profileURL: String
}

let user = User(username: "John", profileURL: "http://google.com")

let json = try? JSONEncoder().encode(user)

if let data = json, let str = String(data: data, encoding: .utf8)?.replacingOccurrences(of: "\\/", with: "/") {
    print(str)
    dump(str)
}

5
投票

我明白了。问题是它不包含任何 \ 字符。这只是 swift 的特性,它总是会在控制台上返回这样的字符串。解决方法是 j-son 解析它。

不过,您可以使用下面的解决方案,将 '\/' 替换为“/”字符串

 let newString = str.replacingOccurrences(of: "\\/", with: "/") 
 print(newString)

2
投票

在使用 JSONEncoder/JSONDecoder 时, 我发现

URL
类型在编码 -> 解码时是有损的。

使用相对于另一个 URL 的字符串进行初始化。

init?(string: String, relativeTo: URL?)

可能对这个苹果文档有帮助:https://developer.apple.com/documentation/foundation/url

使用

PropertyList
版本,但是:

let url = URL(string: "../", relativeTo: URL(string: "http://google.com"))! 
let url2 = PropertyListDecoder().decode([URL].self, from: PropertyListEncoder().encode([User]))

其他方式

let url = URL(string: "../", relativeTo: URL(string: "http://google.com"))! 
let url2 = JSONDecoder().decode([URL].self, from: JSONEncoder().encode([User]))

希望对你有帮助!!


-3
投票

实际上你不能这样做,因为 macOS 和 Linux 的转义系统有点不同。在 Linux 上 // 是允许的,macOS - 不允许(它使用 NSSerialization)。因此,您只需在字符串上添加百分比编码,这可以保证 macOS 和 Linux 上的字符串相同,正确地将字符串发布到服务器并进行正确验证。添加百分比转义集

CharacterSet.urlHostAllowed
。可以这样做:

init(name: String, profile: String){
        username = name
        if let percentedString = profile.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlHostAllowed){
            profileURL = percentedString
        }else{
            profileURL = ""
        }
    }

同样的方式,可以去掉PercentEncoding 而且您不需要修改服务器端!!!

© www.soinside.com 2019 - 2024. All rights reserved.