Rolando
Rolando

Reputation: 62674

What is the best way to get a Swift string into a swift-currency/USD format?

How do I get a string into a 'currency' format USD(xxx)? I am trying to use the following library: https://github.com/peek-travel/swift-currency

I want to be able to take a string:

var testStr1 = "$30.01"
var testStr2 = "$ 30.01"

and convert this into a currency as I have read from several posts using a double or float is bad, but if I start with a String, what else can I convert it to?

I thought I could use the "import Currency" library to do this, but this is not working.

let updatedString = testStr1.replacingOccurrences(of: "$", with: "") 
                        let formatter = NumberFormatter()
                        formatter.locale = Locale.current // USA: Locale(identifier: "en_US")
                        formatter.numberStyle = .decimal
                        let number = formatter.number(from: test)
var dollars = USD(updatedString)

How do I get a string into a 'currency' format USD(xxx)? If there is a better way to accomplish this?

Upvotes: 0

Views: 253

Answers (2)

MadProgrammer
MadProgrammer

Reputation: 347314

The basic concept presented by Himanshu works fine, but your problem isn't necessarily making use of an appropriate formatter, but how to fix your input, as the formatter expects a NSNumber and not a String.

So a quick internet check had me looking at Remove all non-numeric characters from a string in swift

So I could take a String, filter out all the "non numerical" junk and then make a Double out of it.

let input = Double(value.filter("0123456789.".contains))

from there I was able to borrow the concept from Himanshu and make a simple format function

func format(_ value: String, locale: Locale = Locale.current) -> String? {
    
    guard let input = Double(value.filter("0123456789.".contains)) else { return nil }

    //value.trimmingCharacters(in: .whitespacesAndNewlines)
    
    let currencyFormatter = NumberFormatter()
    currencyFormatter.usesGroupingSeparator = true
    currencyFormatter.numberStyle = .currency
    
    currencyFormatter.locale = locale
    
    return currencyFormatter.string(from: NSNumber(value: input))
}

I then made use of a Playground to test it using

var testStr1 = "$30.01"
var testStr2 = "$ 30.01"

format(testStr1, locale: Locale(identifier: "en_US")) // $30.01
format(testStr2, locale: Locale(identifier: "en_US")) // $30.01

format(testStr1, locale: Locale(identifier: "fr_FR")) // 30,01 €
format(testStr2, locale: Locale(identifier: "fr_FR")) // 30,01 €

format(testStr1, locale: Locale(identifier: "de_DE")) // 30,01 €
format(testStr2, locale: Locale(identifier: "de_DE")) // 30,01 €

Now, if you specifically want to use USD(xxx) as the format, then you could simply use a basic NumberFormatter and generate your own String from the resulting conversion of the input to a Double

I have read from several posts using a double or float is bad

So, yes, maintaining a currency value as a Double or Float is generally a bad idea, currency values are typically maintained as a Int or Long, but this is due to how Double and Float representation works in computers, for the, general, presentation, you should be fine, but each use case needs be assessed.

Upvotes: 2

Himanshu Patel
Himanshu Patel

Reputation: 1033

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: 9999.99)!
print(priceString) // Displays $9,999.99 in the US locale

**Forcing a Custom Locale**
You can override the users locale to display specific currency formats by changing the Locale using the identifier.

currencyFormatter.locale = Locale(identifier: "fr_FR")
if let priceString = currencyFormatter.string(from: 9999.99) {
    print(priceString) // Displays 9 999,99 € in the French locale
}

currencyFormatter.locale = Locale(identifier: "de_DE")
if let priceString = currencyFormatter.string(from: 9999.99) {
    print(priceString) // Displays 9.999,99 € in the German locale
}

Upvotes: 1

Related Questions