Swift String escaping when serializing to JSON using Codable

18,984

Solution 1

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.

Solution 2

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

Solution 3

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)

Solution 4

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

Share:
18,984
user_4685247
Author by

user_4685247

Updated on June 17, 2022

Comments

  • user_4685247
    user_4685247 about 2 years

    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.

  • user_4685247
    user_4685247 over 6 years
    As it has been mentioned, the json is signed, adding percent encoding changes the signature and hash
  • Максуд Даудов
    Максуд Даудов over 6 years
    @tofiffe you cannot send url as parameter as it is. Either add removingpercent on server side( which you cannot) or send profileUrl with escaping symbols. Even on Linux, if you create such a string, there is no guarantee you can send to server as it is. If you send it to server with escaping symbols, it will change hash of profile url, right? So what, every time send percented string to validate it or something.
  • user_4685247
    user_4685247 over 6 years
    As I have shown in the question, it does not always return an escaped string (it works fine on Linux machines). When the JSON is parsed the problem is gone, but I need the JSON to be same as on the server
  • skagedal
    skagedal over 5 years
    Thank you for giving an answer (although it's not super-satisfying) and I'm sorry you had too deal with all these people not answering your question and instead wanting you to ask a different question.
  • rustyMagnet
    rustyMagnet over 5 years
    Thanks. This still works. Shame there isn't a more elegant solution. the JSONEncoder APIs must be changing to allow this? People will shout "the JSON standard allows escaping". But I have deadline and a server that does not like the escape character.
  • Vyachaslav Gerchicov
    Vyachaslav Gerchicov over 4 years
    are there ways to achieve the same result with iOS 12?
  • Inder Kumar Rathore
    Inder Kumar Rathore over 4 years
    The others answer may help you.