Экранирование строки Swift при сериализации в JSON с помощью Codable

Я пытаюсь сериализовать свой объект следующим образом:

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 вернуть неоткрытую форму на macOS?

мне нужна строка в JSON, чтобы быть строго без эскапады.

4 ответов


Я закончил с помощью 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)
}

Я понял. Дело в том, что в нем не было никакого характера. Это просто свойство swift, что он всегда будет возвращать такую строку на консоли. Обходной путь-это разбор j-son.

тем не менее, вы можете использовать ниже Решение замены '\/' на "/" string

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

во время игры вокруг JSONEncoder / JSONDecoder, Я обнаружил, что URL тип с потерями на encode - > decode.

инициализируется строкой относительно другого URL-адреса.

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

может помочь этот документ apple: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]))

надеюсь, что будет полезно для вас!!


На самом деле вы не можете этого сделать, так как в macOS и Linux немного разные экранирующие системы. На linux / / разрешено, macOS-нет (он использует NSSerialization). Таким образом, вы можете просто добавить процентную кодировку в свою строку, что гарантирует вам равные строки в macOS и linux, правильную публикацию строки на сервере и правильную проверку. При добавлении процента escaping set CharacterSet.urlHostAllowed. Можно было бы сделать так:

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

таким же образом, вы можете removePercentEncoding И ВАМ НЕ НУЖНО ДОРАБОТАТЬ НА СТОРОНЕ СЕРВЕРА!!!