json - Swift:在保留其密钥和结构的同时匿名化 JSON 内容的最简单、现代的方法是什么?
问题描述
这是我经常遇到的一个问题,但还没有一个好的解决方案。
我想采用具有不同结构和键名的任意 JSON,并通过基于 Swift 的转换运行它:
- 保留键名
- 保留结构,包括原始内容中的空值
- 随机替换我指定的键中的字母数字
- 处理字符串数组
- 处理嵌套结构
我已经成功地使用 Codable 编写了一次性转换,但它需要提前定义整个结构,因此它不适用于任意 JSON。它还需要自定义实现encode(to encoder: Encoder)
来保留空值,这进一步使事情变得笨拙。
另一种方法是使用字符串扫描来检测所需字段并重写其内容吗?使用字典进行某种反思?还有什么?
解决方案
可能这种方式适合您,并进行一些修改。首先,我们需要保留我们想要散列的字段。我把它放在secretFields
. 我们还需要类似 .h 的散列函数randomString
。当然,我们需要递归动态解码HashCodable
。
import Foundation
let jsonData = """{"city":"New York","secret_field": {"first name": "Adam","last name":"Smith"}}"""
// [1]
let secretFIelds = ["first name", "last name"]
// [2]
func randomString(length: Int) -> String {
let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
return String((0..<length).map{ _ in letters.randomElement()! })
}
// [3]
struct HashCodable: Decodable {
var value: Any
struct CodingKeys: CodingKey {
var stringValue: String
var intValue: Int?
init?(intValue: Int) {
self.stringValue = "\(intValue)"
self.intValue = intValue
}
init?(stringValue: String) { self.stringValue = stringValue }
}
init(value: Any) {
self.value = value
}
init(from decoder: Decoder) throws {
if let container = try? decoder.container(keyedBy: CodingKeys.self) {
var result = [String: Any]()
try container.allKeys.forEach { (key) throws in
if secretFIelds.contains(key.stringValue) {
result[key.stringValue] = randomString(length:10)
} else {
result[key.stringValue] =
try container.decode(HashCodable.self, forKey: key).value
}
}
value = result
} else if var container = try? decoder.unkeyedContainer() {
var result = [Any]()
while !container.isAtEnd {
result.append(try container.decode(HashCodable.self).value)
}
value = result
} else if let container = try? decoder.singleValueContainer() {
if let intVal = try? container.decode(Int.self) {
value = intVal
} else if let doubleVal = try? container.decode(Double.self) {
value = doubleVal
} else if let boolVal = try? container.decode(Bool.self) {
value = boolVal
} else if let stringVal = try? container.decode(String.self) {
value = stringVal
} else {
throw DecodingError.dataCorruptedError(
in: container, debugDescription:
"the container contains nothing serialisable")
}
} else {
throw DecodingError.dataCorrupted(
DecodingError.Context(codingPath: decoder.codingPath,
debugDescription: "Could not serialise"))
}
}
}
let decoded = try! JSONDecoder().decode(HashCodable.self, from: jsonData.data(using: .utf8)!)
print(decoded)
输入 JSON:
{ "city":"New York", "secret_field": { "first name": "Adam", "last name": "Smith" } }```
输出:
HashCodable(value: [ "city": "New York", "secret_fields": [ "last name": "3R6ocxYS44", "first name": "uCFgajZQY7" ] ])```
推荐阅读
- c++ - 将 std::unordered_map 值移动到 std::vector
- javascript - 访问对象中的函数
- amazon-web-services - AWS CodeDeploy 部署在 BlockTraffic 事件中失败
- javascript - clearInterval SetInterval 函数未定义
- node.js - 如何在 Jest 中等待 exec 进程完成?
- php - 如何以雄辩的关系与laravel进行求和
- opencv - 较小的 mp4 文件持续时间
- c - 将元素添加到字符串数组
- delphi - Delphi Inline 更改对位读取的回答
- javascript - App.js 中未在 react-native 中呈现的组件。请纠正我。