Swift String escaping when serializing to JSON usi

2019-06-14 21:50发布

问题:

I'm trying to serialize my object as following:

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)
}

However on macOS I'm getting the following:

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

(note escaped '/' character).

While on Linux machines I'm getting:

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

How can I make JSONEncoder return the unescaped form on macOS?

I need the string in JSON to be strictly unescaped.

回答1:

I ended up using replacingOccurrences(of:with:), which may not be the best solution, but it resolves the issue:

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)
}


回答2:

I got it. The thing was that it didn't contain any \ character. It is just the property of swift that it will always return such a string on a console. The workaround is to j-son parse it.

Still, you can be used below solution of replacing '\/' with "/" string

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


回答3:

While playing around JSONEncoder/JSONDecoder, I found that the URL type is lossy on encode -> decode.

Initializes with a string, relative to another URL.

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

Might be help this apple document: https://developer.apple.com/documentation/foundation/url

using the PropertyList version, however:

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

Other way

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

Hope will helpful to you!!



回答4:

Actually you cannot do that since in macOS and Linux are a bit different escaping systems. On linux // is allowed, macOS - not(it uses NSSerialization). So, you can just add percent encoding on your string, which guarantees you equal strings on macOS and linux, right string posting to a server and right validating. On adding percent escaping set CharacterSet.urlHostAllowed. Could be done like this:

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

In the same manner, you can removePercentEncoding AND YOU DONT NEED MODIFY SERVER SIDE!!!