Swift 使用 Codable 序列化为 JSON 时字符串转义
Swift String escaping when serializing to JSON using 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 return 未转义?
我需要 JSON 中的字符串严格不转义。
实际上你不能这样做,因为在 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
而且您不需要修改服务器端!!!
我明白了。问题是它不包含任何 \ 字符。只是 swift 的 属性 它总是在控制台上显示 return 这样的字符串。解决方法是用 j-son 解析它。
不过,您可以使用下面的解决方案将'\/'替换为“/”字符串
let newString = str.replacingOccurrences(of: "\/", with: "/")
print(newString)
在 JSONEncoder/JSONDecoder 玩耍时,
我发现 URL
类型在编码 -> 解码时是有损的。
用一个字符串初始化,相对于另一个 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]))
希望对你有所帮助!!
我最终使用了 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)
}
适用于 iOS 13+ / macOS 10.15+
您可以对 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","username":"John"}
注意: 正如 Martin R 在评论中提到的 \/
是一个有效的 JSON 转义序列。
我正在尝试按如下方式序列化我的对象:
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 return 未转义?
我需要 JSON 中的字符串严格不转义。
实际上你不能这样做,因为在 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 而且您不需要修改服务器端!!!
我明白了。问题是它不包含任何 \ 字符。只是 swift 的 属性 它总是在控制台上显示 return 这样的字符串。解决方法是用 j-son 解析它。
不过,您可以使用下面的解决方案将'\/'替换为“/”字符串
let newString = str.replacingOccurrences(of: "\/", with: "/")
print(newString)
在 JSONEncoder/JSONDecoder 玩耍时,
我发现 URL
类型在编码 -> 解码时是有损的。
用一个字符串初始化,相对于另一个 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]))
希望对你有所帮助!!
我最终使用了 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)
}
适用于 iOS 13+ / macOS 10.15+
您可以对 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","username":"John"}
注意: 正如 Martin R 在评论中提到的 \/
是一个有效的 JSON 转义序列。