简体   繁体   English

在 Swift 中使用 NumberFormatter 进行大十进制数格式化

[英]Large decimal number formatting using NumberFormatter in Swift

I've done this to format the number, but it fails for large numbers我这样做是为了格式化数字,但它对大数字失败

let formatter = NumberFormatter()
formatter.numberStyle = .decimal


    if let number = formatter.number(from: "123456789123456789123") , let str = formatter.string(from:number){

        print(number)
        print(str)
    }

It prints它打印

123456789123456800000
123,456,789,123,456,800,000

It should print它应该打印

123456789123456789123
123,456,789,123,456,789,123

I think there should be the number overflow, is there any alternative to achieve this kind of thing.我认为应该是数字溢出,有没有其他方法可以实现这种事情。

The root of this problem is three-fold:这个问题的根源是三方面的:

  • As of Version 5.6, Swift does not support Decimal literals.从版本 5.6 开始,Swift 不支持十进制文字。
  • Decimal() supports up to 38 digits of precision. Decimal() 支持最多 38 位精度。
  • Double() supports about 17 digits of precision. Double() 支持大约 17 位精度。

Hence when using Decimals to represent numbers with more than 17 digits of precision, it is crucial to never do anything that would convert the Decimal's value to a Double.因此,当使用 Decimals 表示精度超过 17 位的数字时,千万不要做任何会将 Decimal 的值转换为 Double 的事情。 This includes initializing with literals:这包括用文字初始化:

print (Decimal(1234567890.12345678901234567890)) 
// 1234567890.1234569216
print (Decimal(string: "1234567890.12345678901234567890")!) 
// 1234567890.12345678901234567890

Decimal(1234567890.12345678901234567890) produces the value 1234567890.1234569216 because 1234567890.12345678901234567890 is a Double literal, limited to about 17 digits of precision. Decimal(1234567890.12345678901234567890) 产生值 1234567890.1234569216 因为 1234567890.12345678901234567890 是一个 Double 文字,精度限制为大约 17 位数字。

Sadly, NumberFormatter has evidently never gotten the memo on this problem.遗憾的是,NumberFormatter 显然从未收到有关此问题的备忘录。

var dec = Decimal(string: "1234567890.12345678901234567890")!
let f = NumberFormatter()
f.numberStyle = .decimal
f.minimumFractionDigits = 20
print (f.string(from: dec as NSDecimalNumber)!) // 1,234,567,890.12346000000000000000

So at the present time, there is no way to make Swift accurately produce localized, decimal numbers with more than about 17 digits of precision.所以目前,没有办法让 Swift 准确地产生精度超过 17 位的本地化十进制数字。 NumberFormatter cannot produce, for example, the String 1,234,567,890.12345678901234567890 even though Decimal can represent that exact value.例如,NumberFormatter 无法生成字符串 1,234,567,890.12345678901234567890,即使 Decimal 可以表示该精确值。

You can get non-localized string representations of Decimals using String(describing:)您可以使用 String(describing:)

print (String(describing:(Decimal(string: "1234567890.12345678901234567890")!)))
// 1234567890.1234567890123456789

For one of my own apps I made a little "poor man's" Decimal formatter, which simply outputs the full value using the decimal separator from the desired Locale:对于我自己的一个应用程序,我制作了一个“穷人的”小数格式器,它使用所需区域设置中的小数点分隔符简单地输出完整值:

let locale = Locale(identifier: "fr_FR")
dec = Decimal(string: "1234567890,12345678901234567890", locale: locale)!

let formatter = NumberFormatter()
formatter.locale = locale
let localizedSeparator = String(formatter.decimalSeparator.first ?? ".")

let fractionDigits = 20
var strings = String(describing:(dec)).split(separator: (Locale.current.decimalSeparator?.first) ?? "." )
var result = strings[0]
if fractionDigits > 0 {
    if strings.count > 1 {
        while strings[1].count < fractionDigits { strings[1] += "0" }
        result += localizedSeparator + String(strings[1].prefix(fractionDigits))
    }
    else {
        result += localizedSeparator + (0..<fractionDigits).map{_ in "0"}
    }
}

print (result) // 1234567890,12345678901234567890

You could create a Decimal explicitly to work around the mentioned bug您可以显式创建一个Decimal来解决提到的错误

let formatter = NumberFormatter()
formatter.numberStyle = .decimal
if let decimalNumber = Decimal(string: "123456789123456789123"), let str = formatter.string(from:decimalNumber as NSNumber) {
    print(decimalNumber)
    print(str)
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM