【问题标题】:How to format a Double into Currency - Swift 3如何将 Double 格式化为货币 - Swift 3
【发布时间】:2017-05-24 08:27:31
【问题描述】:

我是 Swift 编程的新手,我一直在 Xcode 8.2 中创建一个简单的小费计算器应用程序,我在下面的IBAction 中设置了我的计算。但是当我实际运行我的应用程序并输入一个要计算的数量(例如 23.45)时,它会出现超过 2 个小数位。在这种情况下如何将其格式化为.currency

@IBAction func calculateButtonTapped(_ sender: Any) {

    var tipPercentage: Double {

        if tipAmountSegmentedControl.selectedSegmentIndex == 0 {
            return 0.05
        } else if tipAmountSegmentedControl.selectedSegmentIndex == 1 {
            return 0.10
        } else {
            return 0.2
        }
    }

    let billAmount: Double? = Double(userInputTextField.text!)

    if let billAmount = billAmount {
        let tipAmount = billAmount * tipPercentage
        let totalBillAmount = billAmount + tipAmount

        tipAmountLabel.text = "Tip Amount: $\(tipAmount)"
        totalBillAmountLabel.text = "Total Bill Amount: $\(totalBillAmount)"
    }
}

【问题讨论】:

    标签: ios swift formatting currency


    【解决方案1】:

    如果你想强制货币为$,你可以使用这个字符串初始化器:

    String(format: "Tip Amount: $%.02f", tipAmount)
    

    如果您希望它完全依赖于设备的区域设置,您应该使用NumberFormatter。这将考虑货币的小数位数以及正确定位货币符号。例如。对于 es_ES 语言环境,双精度值 2.4 将返回“2,40€”,对于 jp_JP 语言环境返回“¥ 2”。

    let formatter = NumberFormatter()
    formatter.locale = Locale.current // Change this to another locale if you want to force a specific locale, otherwise this is redundant as the current locale is the default already
    formatter.numberStyle = .currency
    if let formattedTipAmount = formatter.string(from: tipAmount as NSNumber) {
        tipAmountLabel.text = "Tip Amount: \(formattedTipAmount)"
    }
    

    【讨论】:

    • 仅供参考 - 无需将格式化程序的 locale 设置为 Locale.current,因为这是默认设置。
    • 是的,我知道,我添加了一条评论说它是多余的。想把它保留在那里以表明它可以很容易地改变。
    【解决方案2】:

    最好的方法是创建一个NSNumberFormatter。 (NumberFormatter 在 Swift 3 中。)您可以请求货币,它会设置字符串以遵循用户的本地化设置,这很有用。

    作为使用 NumberFormatter 的替代方法,如果您想强制使用美国格式的美元和美分字符串,您可以这样格式化:

    let amount: Double = 123.45
    
    let amountString = String(format: "$%.02f", amount)
    

    【讨论】:

      【解决方案3】:

      方法如下:

          let currentLocale = Locale.current
          let currencySymbol = currentLocale.currencySymbol
          let outputString = "\(currencySymbol)\(String(format: "%.2f", totalBillAmount))"
      

      第一行:您正在获取当前语言环境

      第二行:您正在获取该语言环境的 currencySymbol。 (美元、英镑等)

      第 3 行:使用格式初始化程序将 Double 截断为小数点后 2 位。

      【讨论】:

      • 不要这样做。使用NumberFormatter。这种方法有很多问题,使用NumberFormatter 可以轻松避免。
      • 投反对票,因为例如,我们写的是“10,00 €”,而不是“€10.00”。根据语言环境,价格的写法不同:/
      【解决方案4】:

      除了其他人讨论的NumberFormatterString(format:),您可能需要考虑使用DecimalNSDecimalNumber 并自己控制舍入,从而避免浮点问题。如果您正在做一个简单的小费计算器,那可能没有必要。但是,如果您要在一天结束时将小费加起来,如果您不将数字四舍五入和/或使用十进制数字进行数学运算,则可能会引入错误。

      所以,继续配置您的格式化程序:

      let formatter: NumberFormatter = {
          let _formatter = NumberFormatter()
          _formatter.numberStyle = .decimal
          _formatter.minimumFractionDigits = 2
          _formatter.maximumFractionDigits = 2
          _formatter.generatesDecimalNumbers = true
          return _formatter
      }()
      

      然后,使用十进制数:

      let string = "2.03"
      let tipRate = Decimal(sign: .plus, exponent: -3, significand: 125) // 12.5%
      guard let billAmount = formatter.number(from: string) as? Decimal else { return }
      let tip = (billAmount * tipRate).rounded(2)
      
      guard let output = formatter.string(from: tip as NSDecimalNumber) else { return }
      print("\(output)")
      

      在哪里

      extension Decimal {
      
          /// Round `Decimal` number to certain number of decimal places.
          ///
          /// - Parameters:
          ///   - scale: How many decimal places.
          ///   - roundingMode: How should number be rounded. Defaults to `.plain`.
          /// - Returns: The new rounded number.
      
          func rounded(_ scale: Int, roundingMode: RoundingMode = .plain) -> Decimal {
              var value = self
              var result: Decimal = 0
              NSDecimalRound(&result, &value, scale, roundingMode)
              return result
          }
      }
      

      显然,您可以将上述所有“2 位小数”引用替换为适合您使用的货币的任何数字(或者可能使用变量来表示小数位数)。

      【讨论】:

      • 为什么不对NumberFormatter 使用货币样式?并非所有货币都使用 2 位小数。
      • 是的,你可以这样做。你甚至可以查找你应该四舍五入的小数位数。诚然,使用.currency 会带来其他问题(例如,字符串的解析变得很挑剔;它假设您没有在旅行和处理其他货币等)。根据应用程序的不同,有时让用户指定小数位并完成它会更容易。此外,我的观点不是格式化程序,而是避免使用货币进行浮点数学运算的总法律顾问。
      • 解决舍入问题的另一种方法是将“美元和美分”(或欧元、谢克尔或其他)金额乘以 100(或乘以整个单位中的小数单位数,对于货币没有 100 美分)。然后使用整数数学,并简单地手动格式化输出以插入小数分隔符。这种方法还可以避免浮点错误。
      • 嗯,Decimal 比简单的整数整数要复杂得多。它使用 BCD 表示十进制值,并且一次计算一个十进制数字,而不是使用二进制数学和转换。它还支持小数值。因此,它比二进制浮点数或整数数学要慢很多。对于简单的计算,速度差异无关紧要,但如果您进行大量计算,差异可能会非常显着。
      • 我同意小数的效率可能较低(尽管对于绝大多数应用程序而言并非如此),但恕我直言,它是“如何用货币进行数学运算”问题的正确抽象。
      【解决方案5】:

      你可以这样转换:这个 func convert 随时为你保留 maximumFractionDigits

      static func df2so(_ price: Double) -> String{
              let numberFormatter = NumberFormatter()
              numberFormatter.groupingSeparator = ","
              numberFormatter.groupingSize = 3
              numberFormatter.usesGroupingSeparator = true
              numberFormatter.decimalSeparator = "."
              numberFormatter.numberStyle = .decimal
              numberFormatter.maximumFractionDigits = 2
              return numberFormatter.string(from: price as NSNumber)!
          } 
      

      我在模型类中创建它 然后当你打电话时,你可以接受另一个类,像这样

       print("InitData: result convert string " + Model.df2so(1008977.72))
      //InitData: result convert string "1,008,977.72"
      

      【讨论】:

      • 如果要在每 3 位设置分隔符,请从上面的代码中删除数字样式。
      【解决方案6】:

      如何在 Swift 4 中做到这一点:

      let myDouble = 9999.99
      let currencyFormatter = NumberFormatter()
      currencyFormatter.usesGroupingSeparator = true
      currencyFormatter.numberStyle = .currency
      // localize to your grouping and decimal separator
      currencyFormatter.locale = Locale.current
      
      // We'll force unwrap with the !, if you've got defined data you may need more error checking
      
      let priceString = currencyFormatter.string(from: NSNumber(value: myDouble))!
      print(priceString) // Displays $9,999.99 in the US locale
      

      【讨论】:

        【解决方案7】:

        您可以为字符串或 Int 创建一个扩展,我将展示一个带有字符串的示例

        extension String{
             func toCurrencyFormat() -> String {
                if let intValue = Int(self){
                   let numberFormatter = NumberFormatter()
                   numberFormatter.locale = Locale(identifier: "ig_NG")/* Using Nigeria's Naira here or you can use Locale.current to get current locale, please change to your locale, link below to get all locale identifier.*/ 
                   numberFormatter.numberStyle = NumberFormatter.Style.currency
                   return numberFormatter.string(from: NSNumber(value: intValue)) ?? ""
              }
            return ""
          }
        }
        

        link to get all locale identifier

        【讨论】:

        • 也可以使用Locale.current获取当前设备的locale。
        【解决方案8】:
        extension Float {
            var localeCurrency: String {
                let formatter = NumberFormatter()
                formatter.numberStyle = .currency
                formatter.locale = .current
                return formatter.string(from: self as NSNumber)!
            }
        }
            amount = 200.02
            print("Amount Saved Value ",String(format:"%.2f", amountSaving. localeCurrency))
        

        对我来说它的回报是 0.00! 在我看来,Extension Perfect 访问时返回 0.00!为什么?

        【讨论】:

        • localeCurrency 已经是一个字符串。你为什么要通过字符串初始化器来提供它?
        • 那你为什么要这么做?
        • 我没有正确检查返回类型!
        • 那你要修复它吗?
        • 它还在那里...String(format:"%.2f", amountSaving. localeCurrency)
        【解决方案9】:
         extension String{
            func convertDoubleToCurrency() -> String{
                let amount1 = Double(self)
                let numberFormatter = NumberFormatter()
                numberFormatter.numberStyle = .currency
                numberFormatter.locale = Locale(identifier: "en_US")
                return numberFormatter.string(from: NSNumber(value: amount1!))!
            }
        }
        

        【讨论】:

          【解决方案10】:

          这是我一直在尝试的一种简单方法。

          extension String {
              func toCurrency(Amount: NSNumber) -> String {
                  var currencyFormatter = NumberFormatter()
                  currencyFormatter.usesGroupingSeparator = true
                  currencyFormatter.numberStyle = .currency
                  currencyFormatter.locale = Locale.current
          
                  return currencyFormatter.string(from: Amount)!
              }
          }
          

          如下使用

          let amountToCurrency = NSNumber(99.99)
          String().toCurrency(Amount: amountToCurrency)
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-01-26
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-05-03
            相关资源
            最近更新 更多