简体   繁体   中英

Swift String escaping when serializing to JSON using Codable

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?

I need the string in JSON to be strictly unescaped.

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

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)

For iOS 13+ / macOS 10.15+

You can use .withoutEscapingSlashes option to json decoder to avoid escaping slashes

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

Console O/P

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


NOTE: As mention by Martin R in comments \\/ is a valid JSON escape sequence.

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!!

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!!!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM