Format NSString using NSFormatter - ios

I am getting price of an object in string and I want to formate it as currency.
I am using the following code:
var priceString : NSString = urlDict.objectForKey("price") as NSString
var formatter = NSNumberFormatter()
formatter.numberStyle = .CurrencyStyle
formatter.locale = NSLocale.currentLocale()
let priceNumber = formatter.numberFromString(priceString)
I am getting the data fine in priceString but priceNumber is nil.
And if I try this:
var priceNumber : NSNumber = urlDict.objectForKey("price") as NSNumber
then also the priceNumber is nil.
What approach should I take to achieve a formatted price from the string?

Thanks all for the suggestions:
I have combined above solutions to form a function:
func formatAsPrice(priceString: NSString) -> NSString {
let rsSymbol = "\u{20B9}" // The currency symbol for India
var priceStrTemp = priceString
priceStrTemp = rsSymbol + priceStrTemp
var formatter = NSNumberFormatter()
formatter.numberStyle = .CurrencyStyle
formatter.locale = NSLocale.currentLocale()
formatter.locale = NSLocale(localeIdentifier: "en_IN") //Explicit
formatter.secondaryGroupingSize = 2 // grouping as Indian currency style
let priceNumber = formatter.numberFromString(priceStrTemp)!
var finalPrice: NSString! = (rsSymbol + " \(priceNumber)") as NSString!
return finalPrice
}

The Formatter code is fine.
You have to pass correct Currency string with currency symbol
func format(amount: String) -> NSNumber? {
let formatter = NSNumberFormatter()
formatter.numberStyle = .CurrencyStyle
formatter.locale = NSLocale.currentLocale()
return formatter.numberFromString(amount)
}
format("NOK 12,00") // returns 12.00
format("NOK 12") // Also fine
format("$ 12") // Error, my local currency is NOK (Norwegian krone)
format("12,00") // Error, needs currency symbol in the string.
If you want to parse trying without currency sublime like this "12,00" that you should set currencySymbol to empty string. Like this
func format(amount: String) -> NSNumber? {
let formatter = NSNumberFormatter()
formatter.numberStyle = .CurrencyStyle
formatter.currencySymbol = ""
...
}
format("12,00") // Works fine now

Related

Swift automatically add "." on every 3 digit input in textfield [duplicate]

I am fairly new to Swift and having a great deal of trouble finding a way to add a space as a thousand separator.
What I am hoping to achieve is taking the result of a calculation and displaying it in a textfield so that the format is:
2 358 000
instead of
2358000
for example.
I am not sure if I should be formatting the Int value and then converting it to a String, or adding the space after the Int value is converted to a String. Any help would be greatly appreciated.
You can use NSNumberFormatter to specify a different grouping separator as follow:
update: Xcode 11.5 • Swift 5.2
extension Formatter {
static let withSeparator: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.groupingSeparator = " "
return formatter
}()
}
extension Numeric {
var formattedWithSeparator: String { Formatter.withSeparator.string(for: self) ?? "" }
}
2358000.formattedWithSeparator // "2 358 000"
2358000.99.formattedWithSeparator // "2 358 000.99"
let int = 2358000
let intFormatted = int.formattedWithSeparator // "2 358 000"
let decimal: Decimal = 2358000
let decimalFormatted = decimal.formattedWithSeparator // "2 358 000"
let decimalWithFractionalDigits: Decimal = 2358000.99
let decimalWithFractionalDigitsFormatted = decimalWithFractionalDigits.formattedWithSeparator // "2 358 000.99"
If you need to display your value as currency with current locale or with a fixed locale:
extension Formatter {
static let number = NumberFormatter()
}
extension Locale {
static let englishUS: Locale = .init(identifier: "en_US")
static let frenchFR: Locale = .init(identifier: "fr_FR")
static let portugueseBR: Locale = .init(identifier: "pt_BR")
// ... and so on
}
extension Numeric {
func formatted(with groupingSeparator: String? = nil, style: NumberFormatter.Style, locale: Locale = .current) -> String {
Formatter.number.locale = locale
Formatter.number.numberStyle = style
if let groupingSeparator = groupingSeparator {
Formatter.number.groupingSeparator = groupingSeparator
}
return Formatter.number.string(for: self) ?? ""
}
// Localized
var currency: String { formatted(style: .currency) }
// Fixed locales
var currencyUS: String { formatted(style: .currency, locale: .englishUS) }
var currencyFR: String { formatted(style: .currency, locale: .frenchFR) }
var currencyBR: String { formatted(style: .currency, locale: .portugueseBR) }
// ... and so on
var calculator: String { formatted(groupingSeparator: " ", style: .decimal) }
}
Usage:
1234.99.currency // "$1,234.99"
1234.99.currencyUS // "$1,234.99"
1234.99.currencyFR // "1 234,99 €"
1234.99.currencyBR // "R$ 1.234,99"
1234.99.calculator // "1 234.99"
Note: If you would like to have a space with the same width of a period you can use "\u{2008}"
unicode spaces
formatter.groupingSeparator = "\u{2008}"
You want to use NSNumberFormatter:
let fmt = NSNumberFormatter()
fmt.numberStyle = .DecimalStyle
fmt.stringFromNumber(2358000) // with my locale, "2,358,000"
fmt.locale = NSLocale(localeIdentifier: "fr_FR")
fmt.stringFromNumber(2358000) // "2 358 000"
With Swift 5, when you need to format the display of numbers, NumberFormatter is the right tool.
NumberFormatter has a property called numberStyle. numberStyle can be set to a value of NumberFormatter.Style.decimal in order to set the formatter's style to decimal.
Therefore, in the simplest case when you want to format a number with decimal style, you can use the following Playground code:
import Foundation
let formatter = NumberFormatter()
formatter.numberStyle = NumberFormatter.Style.decimal
let amount = 2358000
let formattedString = formatter.string(for: amount)
print(String(describing: formattedString))
According to the user's current locale, this code will print Optional("2,358,000") for en_US or Optional("2 358 000") for fr_FR.
Note that the following code snippet that uses the NumberFormatter's locale property set to Locale.current is equivalent to the previous Playground code:
import Foundation
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.locale = Locale.current
let amount = 2358000
let formattedString = formatter.string(for: amount)
print(String(describing: formattedString))
The Playground code below that uses the NumberFormatter's groupingSeparator property set to Locale.current.groupingSeparator is also equivalent to the former:
import Foundation
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.groupingSeparator = Locale.current.groupingSeparator
let amount = 2358000
let formattedString = formatter.string(for: amount)
print(String(describing: formattedString))
Otherwise, if you want to set the number formatting with a specific locale formatting style, you may use the following Playground code:
import Foundation
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.locale = Locale(identifier: "fr_FR")
let amount = 2358000
let formattedString = formatter.string(for: amount)
print(String(describing: formattedString))
// prints: Optional("2 358 000")
However, if what you really want is to enforce a specific grouping separator, you may use the Playground code below:
import Foundation
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.groupingSeparator = " "
let amount = 2358000
let formattedString = formatter.string(for: amount)
print(String(describing: formattedString))
// prints: Optional("2 358 000")
Leo Dabus's answer translated to Swift 3:
Into any .swift file, out of a class:
struct Number {
static let withSeparator: NumberFormatter = {
let formatter = NumberFormatter()
formatter.groupingSeparator = " " // or possibly "." / ","
formatter.numberStyle = .decimal
return formatter
}()
}
extension Integer {
var stringWithSepator: String {
return Number.withSeparator.string(from: NSNumber(value: hashValue)) ?? ""
}
}
Usage:
let myInteger = 2358000
let myString = myInteger.stringWithSeparator // "2 358 000"
Code:
//5000000
let formatter = NumberFormatter()
formatter.groupingSeparator = " "
formatter.locale = Locale(identifier: "en_US")
formatter.numberStyle = .decimal.
Output:
5 000 000
I was looking for a currency format like $100,000.00
I accomplished it customizing the implementation Leo Dabus like this
extension Formatter {
static let withSeparator: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.currencyGroupingSeparator = ","
formatter.locale = Locale(identifier: "en_US") //for USA's currency patter
return formatter
}()
}
extension Numeric {
var formattedWithSeparator: String {
return Formatter.withSeparator.string(for: self) ?? ""
}
}
Try this
func addPoints(inputNumber: NSMutableString){
var count: Int = inputNumber.length
while count >= 4 {
count = count - 3
inputNumber.insert(" ", at: count) // you also can use ","
}
print(inputNumber)
}
The call:
addPoints(inputNumber: "123456")
The result:
123 456 (or 123,456)

Issue in converting float to currency String formatter

Extenstion for converter Swift 4.2
extension Float {
var localeCurrency: String {
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.locale = .current
return formatter.string(from: self as NSNumber)!
}
}
Accessing the value
let amount = 200.02
print("Amount Saved Value ",String(format:"%.2f", amountSaving. localeCurrency))
For me Its return 0.00!
Looks to me Extenstion Perfect when accessing it return 0.00! Why?

How to force currency format locale to specific country in swift [duplicate]

I am creating a budget app that allows the user to input their budget as well as transactions. I need to allow the user to enter both pence and pounds from separate text fields and they need to be formatted together with currency symbols. I have this working fine at the moment but would like to make it localised as currently it only works with GBP. I have been struggling to convert NSNumberFormatter examples from Objective-C to Swift.
My first issue is the fact that I need to set the placeholders for the input fields to be specific to the users location. Eg. Pounds and Pence, Dollars and Cents etc...
The second issue is that the values inputted in each of the text fields such as 10216 and 32 need to be formatted and the currency symbol specific to the users location needs to be added. So it would become £10,216.32 or $10,216.32 etc...
Also, I need to use the result of the formatted number in a calculation. So how can I do this without running into issues without running into issues with the currency symbol?
Here's an example on how to use it on Swift 3.
( Edit: Works in Swift 5 too )
let price = 123.436 as NSNumber
let formatter = NumberFormatter()
formatter.numberStyle = .currency
// formatter.locale = NSLocale.currentLocale() // This is the default
// In Swift 4, this ^ was renamed to simply NSLocale.current
formatter.string(from: price) // "$123.44"
formatter.locale = Locale(identifier: "es_CL")
formatter.string(from: price) // $123"
formatter.locale = Locale(identifier: "es_ES")
formatter.string(from: price) // "123,44 €"
Here's the old example on how to use it on Swift 2.
let price = 123.436
let formatter = NSNumberFormatter()
formatter.numberStyle = .CurrencyStyle
// formatter.locale = NSLocale.currentLocale() // This is the default
formatter.stringFromNumber(price) // "$123.44"
formatter.locale = NSLocale(localeIdentifier: "es_CL")
formatter.stringFromNumber(price) // $123"
formatter.locale = NSLocale(localeIdentifier: "es_ES")
formatter.stringFromNumber(price) // "123,44 €"
Swift 3:
If you are looking for a solution that gives you:
"5" = "$5"
"5.0" = "$5"
"5.00" = "$5"
"5.5" = "$5.50"
"5.50" = "$5.50"
"5.55" = "$5.55"
"5.234234" = "5.23"
Please use the following:
func cleanDollars(_ value: String?) -> String {
guard value != nil else { return "$0.00" }
let doubleValue = Double(value!) ?? 0.0
let formatter = NumberFormatter()
formatter.currencyCode = "USD"
formatter.currencySymbol = "$"
formatter.minimumFractionDigits = (value!.contains(".00")) ? 0 : 2
formatter.maximumFractionDigits = 2
formatter.numberStyle = .currencyAccounting
return formatter.string(from: NSNumber(value: doubleValue)) ?? "$\(doubleValue)"
}
I have implemented the solution provided by #NiñoScript as an extension as well:
Extension
// Create a string with currency formatting based on the device locale
//
extension Float {
var asLocaleCurrency:String {
var formatter = NSNumberFormatter()
formatter.numberStyle = .CurrencyStyle
formatter.locale = NSLocale.currentLocale()
return formatter.stringFromNumber(self)!
}
}
Usage:
let amount = 100.07
let amountString = amount.asLocaleCurrency
print(amount.asLocaleCurrency())
// prints: "$100.07"
Swift 3
extension Float {
var asLocaleCurrency:String {
var formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.locale = Locale.current
return formatter.string(from: self)!
}
}
Xcode 11 • Swift 5.1
extension Locale {
static let br = Locale(identifier: "pt_BR")
static let us = Locale(identifier: "en_US")
static let uk = Locale(identifier: "en_GB") // ISO Locale
}
extension NumberFormatter {
convenience init(style: Style, locale: Locale = .current) {
self.init()
self.locale = locale
numberStyle = style
}
}
extension Formatter {
static let currency = NumberFormatter(style: .currency)
static let currencyUS = NumberFormatter(style: .currency, locale: .us)
static let currencyBR = NumberFormatter(style: .currency, locale: .br)
}
extension Numeric {
var currency: String { Formatter.currency.string(for: self) ?? "" }
var currencyUS: String { Formatter.currencyUS.string(for: self) ?? "" }
var currencyBR: String { Formatter.currencyBR.string(for: self) ?? "" }
}
let price = 1.99
print(Formatter.currency.locale) // "en_US (current)\n"
print(price.currency) // "$1.99\n"
Formatter.currency.locale = .br
print(price.currency) // "R$1,99\n"
Formatter.currency.locale = .uk
print(price.currency) // "£1.99\n"
print(price.currencyBR) // "R$1,99\n"
print(price.currencyUS) // "$1.99\n"
Details
Xcode 10.2.1 (10E1001), Swift 5
Solution
import Foundation
class CurrencyFormatter {
static var outputFormatter = CurrencyFormatter.create()
class func create(locale: Locale = Locale.current,
groupingSeparator: String? = nil,
decimalSeparator: String? = nil,
style: NumberFormatter.Style = NumberFormatter.Style.currency) -> NumberFormatter {
let outputFormatter = NumberFormatter()
outputFormatter.locale = locale
outputFormatter.decimalSeparator = decimalSeparator ?? locale.decimalSeparator
outputFormatter.groupingSeparator = groupingSeparator ?? locale.groupingSeparator
outputFormatter.numberStyle = style
return outputFormatter
}
}
extension Numeric {
func toCurrency(formatter: NumberFormatter = CurrencyFormatter.outputFormatter) -> String? {
guard let num = self as? NSNumber else { return nil }
var formatedSting = formatter.string(from: num)
guard let locale = formatter.locale else { return formatedSting }
if let separator = formatter.groupingSeparator, let localeValue = locale.groupingSeparator {
formatedSting = formatedSting?.replacingOccurrences(of: localeValue, with: separator)
}
if let separator = formatter.decimalSeparator, let localeValue = locale.decimalSeparator {
formatedSting = formatedSting?.replacingOccurrences(of: localeValue, with: separator)
}
return formatedSting
}
}
Usage
let price = 12423.42
print(price.toCurrency() ?? "")
CurrencyFormatter.outputFormatter = CurrencyFormatter.create(style: .currencyISOCode)
print(price.toCurrency() ?? "nil")
CurrencyFormatter.outputFormatter = CurrencyFormatter.create(locale: Locale(identifier: "es_ES"))
print(price.toCurrency() ?? "nil")
CurrencyFormatter.outputFormatter = CurrencyFormatter.create(locale: Locale(identifier: "de_DE"), groupingSeparator: " ", style: .currencyISOCode)
print(price.toCurrency() ?? "nil")
CurrencyFormatter.outputFormatter = CurrencyFormatter.create(groupingSeparator: "_", decimalSeparator: ".", style: .currencyPlural)
print(price.toCurrency() ?? "nil")
let formatter = CurrencyFormatter.create(locale: Locale(identifier: "de_DE"), groupingSeparator: " ", decimalSeparator: ",", style: .currencyPlural)
print(price.toCurrency(formatter: formatter) ?? "nil")
Results
$12,423.42
USD12,423.42
12.423,42 €
12 423,42 EUR
12_423.42 US dollars
12 423,42 Euro
Updated for Swift 4 from #Michael Voccola's answer:
extension Double {
var asLocaleCurrency: String {
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.locale = Locale.current
let formattedString = formatter.string(from: self as NSNumber)
return formattedString ?? ""
}
}
Note: no force-unwraps, force-unwraps are evil.
Swift 4 TextField Implemented
var value = 0
currencyTextField.delegate = self
func numberFormatting(money: Int) -> String {
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.locale = .current
return formatter.string(from: money as NSNumber)!
}
currencyTextField.text = formatter.string(from: 50 as NSNumber)!
func textFieldDidEndEditing(_ textField: UITextField) {
value = textField.text
textField.text = numberFormatting(money: Int(textField.text!) ?? 0 as! Int)
}
func textFieldDidBeginEditing(_ textField: UITextField) {
textField.text = value
}
extension Float {
var convertAsLocaleCurrency :String {
var formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.locale = Locale.current
return formatter.string(from: self as NSNumber)!
}
}
This working for swift 3.1 xcode 8.2.1
Swift 4
formatter.locale = Locale.current
if you want to change locale you can do it like this
formatter.locale = Locale.init(identifier: "id-ID")
// This is locale for Indonesia locale. if you want use as per mobile phone area use it as per upper mention Locale.current
//MARK:- Complete code
let formatter = NumberFormatter()
formatter.numberStyle = .currency
if let formattedTipAmount = formatter.string(from: Int(newString)! as
NSNumber) {
yourtextfield.text = formattedTipAmount
}
add this function
func addSeparateMarkForNumber(int: Int) -> String {
var string = ""
let formatter = NumberFormatter()
formatter.locale = Locale.current
formatter.numberStyle = .decimal
if let formattedTipAmount = formatter.string(from: int as NSNumber) {
string = formattedTipAmount
}
return string
}
using:
let giaTri = value as! Int
myGuessTotalCorrect = addSeparateMarkForNumber(int: giaTri)

How to use currencyFormatter with a decimal

I'm trying to take a decimal I'm storing in CoreData and run it through the currency formatter in Swift 3. Here is what I'm trying to use:
var currencyFormatter = NumberFormatter()
currencyFormatter.usesGroupingSeparator = true
currencyFormatter.numberStyle = NumberFormatter.Style.currency
// localize to your grouping and decimal separator
currencyFormatter.locale = NSLocale.current
var priceString = currencyFormatter.stringFromNumber(NSNumber(totalAmount))
Where totalAmount is the decimal I'm using for CoreData.
But . I get this error when trying to convert my decimal to a NSNumber()
Argument labels '(_:)' do not match any available overloads
stringFromNumber got renamed to string(from:), e.g.
var priceString = currencyFormatter.string(from: NSNumber(totalAmount))
but you don't have to convert to NSNumber
var priceString = currencyFormatter.string(for: totalAmount)
You can have something like:
class YourClass: UIViewController {
static let priceFormatter: NumberFormatter = {
let formatter = NumberFormatter()
formatter.formatterBehavior = .behavior10_4
formatter.numberStyle = .currency
return formatter
}()
}
Usage:
yourLabel.text = YourClass.priceFormatter.string(from: totalAmount)

Changing grouping separator, currency symbol and position of currency symbol for multiple currencies in Swift

My app uses multiple currencies, and these currencies uses different formats, for example:
Price for Ruble shows as: 1,101 Руб.
Same amount for US Dollar shows as: US $1 101
How would I change the grouping separator, currency symbol and position of currency symbol, by defining a set of different formats for different currencies.
This is how my short code stands
var formatter = NSNumberFormatter()
formatter.numberStyle = .CurrencyStyle
formatter.locale = NSLocale.currentLocale()
formatter.stringFromNumber(4500000)
//Output : $4,500,000.00
//Expected : 4,500,000 Руб.
Swift 4 or later
extension Formatter {
static let belarusianRuble: NumberFormatter = {
let formatter = NumberFormatter()
// set the numberStyle to .CurrencyStyle
formatter.numberStyle = .currency
// set the desired negative and positive formats grouping, and currency symbol position
formatter.positiveFormat = "#,##0 ¤"
formatter.negativeFormat = "-#,##0 ¤"
// set your custom currency symbol
formatter.currencySymbol = "Руб"
return formatter
}()
}
let stringToDisplay = Formatter.belarusianRuble.string(for: 4500000) // "4,500,000 Руб"
extension Formatter {
static let currencyBYR: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.positiveFormat = "#,##0 ¤"
formatter.negativeFormat = "-#,##0 ¤"
formatter.currencySymbol = "Руб"
return formatter
}()
static let currencyEUR: NumberFormatter = {
let formatter = NumberFormatter()
formatter.locale = Locale(identifier: "pt_PT")
formatter.numberStyle = .currency
return formatter
}()
static let currencyUSD: NumberFormatter = {
let formatter = NumberFormatter()
formatter.locale = Locale(identifier: "en_US")
formatter.numberStyle = .currency
return formatter
}()
static let currencyBRL: NumberFormatter = {
let formatter = NumberFormatter()
formatter.locale = Locale(identifier: "pt_BR")
formatter.numberStyle = .currency
return formatter
}()
static let currencyRUB: NumberFormatter = {
let formatter = NumberFormatter()
formatter.locale = Locale(identifier: "ru_RU")
formatter.numberStyle = .currency
formatter.maximumFractionDigits = 0
return formatter
}()
static let currencyLocale: NumberFormatter = {
let formatter = NumberFormatter()
formatter.locale = .current
formatter.numberStyle = .currency
return formatter
}()
}
extension Numeric {
var currencyLocale: String { return Formatter.currencyLocale.string(for: self) ?? "" }
var currencyUSD: String { return Formatter.currencyUSD.string(for: self) ?? "" }
var currencyEUR: String { return Formatter.currencyEUR.string(for: self) ?? "" }
var currencyBYR: String { return Formatter.currencyBYR.string(for: self) ?? "" }
var currencyBRL: String { return Formatter.currencyBRL.string(for: self) ?? "" }
var currencyRUB: String { return Formatter.currencyRUB.string(for: self) ?? "" }
}
Usage
let amount = 4500000.0
let stringLocale = amount.currencyLocale // "$4,500,000.00"
let stringUSD = amount.currencyUSD // "$4,500,000.00"
let stringEUR = amount.currencyEUR // "4 500 000,00 €"
let stringBRL = amount.currencyBRL // "R$ 4.500.000,00"
let stringBYR = amount.currencyBYR // "4,500,000 Руб"
let stringRUB = amount.currencyRUB // "4 500 000 ₽"
I ended up with Currency class that uses current locale decimal/thousands/grouping separators (thanks to #jcaron recommendation in comments)
The class offers few customization, which fits my task:
Currency symbol
Minimum/maximum fraction digits
Positioning symbol either left/right
class Currency {
var formatter = NumberFormatter()
var symbol: String
var isRTL: Bool
init(_ currencySymbol: String, minFractionDigits: Int, maxFractionDigits: Int, isRTL: Bool) {
self.formatter.currencySymbol = ""
self.formatter.minimumFractionDigits = minFractionDigits
self.formatter.maximumFractionDigits = maxFractionDigits
self.formatter.numberStyle = .currency
self.symbol = currencySymbol
self.isRTL = isRTL
}
func beautify(_ price: Double) -> String {
let str = self.formatter.string(from: NSNumber(value: price))!
if self.isRTL {
return str + self.symbol
}
return self.symbol + str
}
}
Initialize required formatters
struct CurrencyFormatter {
static let byr = Currency(" Руб.", minFractionDigits: 2, maxFractionDigits: 2, isRTL: true)
static let usd = Currency("US $", minFractionDigits: 2, maxFractionDigits: 2, isRTL: false)
static let rub = Currency("\u{20BD} ", minFractionDigits: 0, maxFractionDigits: 1, isRTL: false)
}
Usage
CurrencyFormatter.byr.beautify(12345.67) // Output: 12 345,67 Руб.
CurrencyFormatter.usd.beautify(12345.67) // Output: US $12 345,67
CurrencyFormatter.rub.beautify(12345.67) // Output: ₽ 12 345,7

Resources