Ene*_*nso 3 double serialization json decimal swift
NumberFormatter 在屏幕上显示值时,可以很容易地格式化货币:
let decimal = Decimal(25.99)
let decimalNumberFormatter = NumberFormatter()
decimalNumberFormatter.numberStyle = .currencyAccounting
let output = decimalNumberFormatter.string(for: decimal)
// output = "$25.99"
Run Code Online (Sandbox Code Playgroud)
上面的代码适用于任何Decimal或Double值.十进制数字总是与正在使用的语言环境匹配.
我们认为将浮点货币值序列化为JSON并不是那么简单.
具有以下序列化方法(介意力量展开):
func serialize(prices: Any...) {
let data = try! JSONSerialization.data(withJSONObject: ["value": prices], options: [])
let string = String(data: data, encoding: .utf8)!
print(string)
}
Run Code Online (Sandbox Code Playgroud)
然后我们可以使用不同的值和类型来调用它.Double,Decimal和NSDecimalNumber(应该从Swift的桥接Decimal)在某些情况下无法正确呈现值.
serialize(prices: 125.99, 16.42, 88.56, 88.57, 0.1 + 0.2)
// {"value":[125.99,16.42,88.56,88.56999999999999,0.3]}
serialize(prices: Decimal(125.99), Decimal(16.42), Decimal(88.56), Decimal(88.57), Decimal(0.1) + Decimal(0.2))
// {"value":[125.98999999999997952,16.420000000000004096,88.56,88.57,0.3]}
serialize(prices: NSDecimalNumber(value: 125.99), NSDecimalNumber(value: 16.42), NSDecimalNumber(value: 88.56), NSDecimalNumber(value: 88.57), NSDecimalNumber(value: 0.1).adding(NSDecimalNumber(value: 0.2)))
// {"value":[125.98999999999997952,16.420000000000004096,88.56,88.57,0.3]}
Run Code Online (Sandbox Code Playgroud)
我不打算将数字序列化为货币(不需要货币符号,整数(5)或单个小数位(0.3)都可以.但是,我正在寻找一种解决方案,其中序列化输出包含的不超过给定货币(区域设置)允许的小数位数.
这是否有任何方法可以限制或指定将浮点值序列化为JSON时要使用的小数位数?
更新#1:
有更多的数据类型测试,令人惊讶的好像都Float和Float32两个小数货币工作.Float64失败Double(可能是同一类型的别名).
serialize(prices: Float(125.99), Float(16.42), Float(88.56), Float(88.57), Float(0.1) + Float(0.2))
// {"value":[125.99,16.42,88.56,88.57,0.3]}
serialize(prices: Float32(125.99), Float32(16.42), Float32(88.56), Float32(88.57), Float32(0.1) + Float32(0.2))
// {"value":[125.99,16.42,88.56,88.57,0.3]}
serialize(prices: Float64(125.99), Float64(16.42), Float64(88.56), Float64(88.57), Float64(0.1) + Float64(0.2))
// {"value":[125.99,16.42,88.56,88.56999999999999,0.3]}
Run Code Online (Sandbox Code Playgroud)
但是,很难知道它们在所有情况下是否都能正常工作.Float80无法序列化_NSJSONWriter异常.
在对此问题进行一些研究后,同事发现使用NSDecimalNumberHandler解决JSON序列化问题来舍入指定行为的值.
fileprivate let currencyBehavior = NSDecimalNumberHandler(roundingMode: .bankers, scale: 2, raiseOnExactness: false, raiseOnOverflow: false, raiseOnUnderflow: false, raiseOnDivideByZero: true)
extension Decimal {
var roundedCurrency: Decimal {
return (self as NSDecimalNumber).rounding(accordingToBehavior: currencyBehavior) as Decimal
}
}
Run Code Online (Sandbox Code Playgroud)
按照帖子中的示例代码,我们得到了所需的输出:
serialize(prices: Decimal(125.99).roundedCurrency, Decimal(16.42).roundedCurrency, Decimal(88.56).roundedCurrency, Decimal(88.57).roundedCurrency, (Decimal(0.1) + Decimal(0.2)).roundedCurrency)
// {"value":[125.99,16.42,88.56,88.57,0.3]}
Run Code Online (Sandbox Code Playgroud)
有用!测试10000个值(从0.0到99.99)并没有发现任何问题.
如果需要,可以将比例调整为当前语言环境中的小数位数:
var currencyFormatter = NumberFormatter()
currencyFormatter.numberStyle = .currencyAccounting
let scale = currencyFormatter.maximumFractionDigits
// scale == 2
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2047 次 |
| 最近记录: |