NumberFormatter 和货币字符串的欧元错误
Euro errors with NumberFormatter and Currency Strings
我在 Swift(字符串扩展)中编写了一个函数来获取任何货币字符串,例如“$500.00”或“250,75 €”,甚至是“500”,然后 return来自它的 nsdecimalnumber。
不幸的是,当我传入“250,75 €”时,它命中了我代码的 if (nf.number(from: self) == nil) 部分并评估为 nil,因此 return什么都没有。它似乎只在您用逗号添加更改时发生,例如 250,75。但是,如果我做了 250,它就会起作用。它似乎只为欧元这样做。美元运作良好($500.00、125.75 等)
这是我的代码。有什么想法吗?感谢您的宝贵时间!
extension String{
func toDecimalFromCurrencyString() -> NSDecimalNumber
{
let nf = NumberFormatter()
nf.numberStyle = NumberFormatter.Style.currency
nf.formatterBehavior = NumberFormatter.Behavior.behavior10_4
nf.generatesDecimalNumbers = true
var test = self.replacingOccurrences(of: nf.currencySymbol!, with: "", options: NSString.CompareOptions.literal, range: nil)
test = test.replacingOccurrences(of: nf.currencyDecimalSeparator!, with: "", options: NSString.CompareOptions.literal, range: nil)
test = test.replacingOccurrences(of: nf.currencyGroupingSeparator!, with: "", options: NSString.CompareOptions.literal, range: nil)
let scanner: Scanner = Scanner(string:test)
let isNumeric = (scanner.scanDecimal(nil) && scanner.isAtEnd)
//If the string entered isn't numeric (for example ... or $$$, then fail)
if (self.trimmingCharacters(in: CharacterSet.whitespaces).utf16.count == 0 || (!isNumeric))
{
return 0.0
}
//If the string contains more than one decimal separator (.), or more than one currency symbol ($), return 0.0
else if ((self.components(separatedBy: nf.currencyDecimalSeparator!).count-1) > 1 || (self.components(separatedBy: nf.currencySymbol!).count - 1) > 1) {
return 0.0
}
//If the string contains more than one consecutive currency grouping separator (i.e. ,,) then return 0.0
else if ((components(separatedBy: nf.currencyGroupingSeparator! + nf.currencyGroupingSeparator!).count-1) > 0)
{
return 0.0
}
else
{
if (nf.number(from: self) == nil) {
return 0.00
}
else {
return nf.number(from: self) as! NSDecimalNumber
}
}
}
}
您可以简单地 trim 字符串中的所有非数字并使用两个数字格式化程序,一个带点,另一个带逗号,并在链中使用 nil 合并运算符,如下所示:
extension Formatter {
static let decimalWithDotSeparator: NumberFormatter = {
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
numberFormatter.decimalSeparator = "."
return numberFormatter
}()
static let decimalWithCommaSeparator: NumberFormatter = {
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
numberFormatter.decimalSeparator = ","
return numberFormatter
}()
}
extension String {
var numberFromCurrency: NSDecimalNumber? {
var string = self
while let first = string.characters.first, Int("\(first)") == nil {
string = String(string.characters.dropFirst())
}
while let last = string.characters.last, Int("\(last)") == nil {
string = String(string.characters.dropLast())
}
return (Formatter.decimalWithDotSeparator.number(from: string) ??
Formatter.decimalWithCommaSeparator.number(from: string) ?? 0)
.decimalValue.decimalNumber
}
}
extension Decimal {
var decimalNumber: NSDecimalNumber { return NSDecimalNumber(decimal: self) }
}
let dollar = "9.99"
dollar.numberFromCurrency // 249.99
let real = "R9,99"
real.numberFromCurrency // 249.99
let euro = "0,50€"
euro.numberFromCurrency // 0.5
我在 Swift(字符串扩展)中编写了一个函数来获取任何货币字符串,例如“$500.00”或“250,75 €”,甚至是“500”,然后 return来自它的 nsdecimalnumber。
不幸的是,当我传入“250,75 €”时,它命中了我代码的 if (nf.number(from: self) == nil) 部分并评估为 nil,因此 return什么都没有。它似乎只在您用逗号添加更改时发生,例如 250,75。但是,如果我做了 250,它就会起作用。它似乎只为欧元这样做。美元运作良好($500.00、125.75 等)
这是我的代码。有什么想法吗?感谢您的宝贵时间!
extension String{
func toDecimalFromCurrencyString() -> NSDecimalNumber
{
let nf = NumberFormatter()
nf.numberStyle = NumberFormatter.Style.currency
nf.formatterBehavior = NumberFormatter.Behavior.behavior10_4
nf.generatesDecimalNumbers = true
var test = self.replacingOccurrences(of: nf.currencySymbol!, with: "", options: NSString.CompareOptions.literal, range: nil)
test = test.replacingOccurrences(of: nf.currencyDecimalSeparator!, with: "", options: NSString.CompareOptions.literal, range: nil)
test = test.replacingOccurrences(of: nf.currencyGroupingSeparator!, with: "", options: NSString.CompareOptions.literal, range: nil)
let scanner: Scanner = Scanner(string:test)
let isNumeric = (scanner.scanDecimal(nil) && scanner.isAtEnd)
//If the string entered isn't numeric (for example ... or $$$, then fail)
if (self.trimmingCharacters(in: CharacterSet.whitespaces).utf16.count == 0 || (!isNumeric))
{
return 0.0
}
//If the string contains more than one decimal separator (.), or more than one currency symbol ($), return 0.0
else if ((self.components(separatedBy: nf.currencyDecimalSeparator!).count-1) > 1 || (self.components(separatedBy: nf.currencySymbol!).count - 1) > 1) {
return 0.0
}
//If the string contains more than one consecutive currency grouping separator (i.e. ,,) then return 0.0
else if ((components(separatedBy: nf.currencyGroupingSeparator! + nf.currencyGroupingSeparator!).count-1) > 0)
{
return 0.0
}
else
{
if (nf.number(from: self) == nil) {
return 0.00
}
else {
return nf.number(from: self) as! NSDecimalNumber
}
}
}
}
您可以简单地 trim 字符串中的所有非数字并使用两个数字格式化程序,一个带点,另一个带逗号,并在链中使用 nil 合并运算符,如下所示:
extension Formatter {
static let decimalWithDotSeparator: NumberFormatter = {
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
numberFormatter.decimalSeparator = "."
return numberFormatter
}()
static let decimalWithCommaSeparator: NumberFormatter = {
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
numberFormatter.decimalSeparator = ","
return numberFormatter
}()
}
extension String {
var numberFromCurrency: NSDecimalNumber? {
var string = self
while let first = string.characters.first, Int("\(first)") == nil {
string = String(string.characters.dropFirst())
}
while let last = string.characters.last, Int("\(last)") == nil {
string = String(string.characters.dropLast())
}
return (Formatter.decimalWithDotSeparator.number(from: string) ??
Formatter.decimalWithCommaSeparator.number(from: string) ?? 0)
.decimalValue.decimalNumber
}
}
extension Decimal {
var decimalNumber: NSDecimalNumber { return NSDecimalNumber(decimal: self) }
}
let dollar = "9.99"
dollar.numberFromCurrency // 249.99
let real = "R9,99"
real.numberFromCurrency // 249.99
let euro = "0,50€"
euro.numberFromCurrency // 0.5