77

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.

Mick MacCallum
  • 129,200
  • 40
  • 280
  • 281
alionthego
  • 8,508
  • 9
  • 52
  • 125

7 Answers7

179

edit/update: Using the new generic formatted method (iOS15+/Xcode 13.0+):

current locale

2358000.formatted()      // "2,358,000"

fixed locales

2358000.formatted(.number.locale(.init(identifier: "fr_FR")))  // "2 358 000"
2358000.formatted(.number.locale(.init(identifier: "pt_BR")))  // "2.358.000"

original post

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}"
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
37

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"
Airspeed Velocity
  • 40,491
  • 8
  • 113
  • 118
  • I didn't know that France (or any country, for that matter) used spaces as the separator. My favorite style has always been spaces every 3 digits, period between the whole and decimal portion... I picked it up from an old math book and have never seen it used anywhere else... is that exactly what the French do? – ArtOfWarfare Apr 10 '16 at 19:52
  • @ArtOfWarfare many languages use comma as the decimal separator, but vary between space and period for the thousands separator (e.g. French and German use a space, Spanish and Italian use a period). I think English is in the minority (maybe of one?) using a period for the decimal. – Airspeed Velocity Apr 10 '16 at 20:39
  • @AirspeedVelocity Actually, in German language a period (.) as thousands separator and a comma (,) as decimas separator are used. So 1,234.56 in English is 1.234,56 in German. – Manuel Jan 17 '17 at 23:25
  • Italy: period is for thousands (1.000), comma is for decimal. This highlights the need to let the formatter format the format and format the formatter yourself. –  Dec 26 '18 at 18:13
25

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")
Imanou Petit
  • 89,880
  • 29
  • 256
  • 218
11

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"
David Seek
  • 16,783
  • 19
  • 105
  • 136
1

Code:

//5000000
let formatter = NumberFormatter()
formatter.groupingSeparator = " "
formatter.locale = Locale(identifier: "en_US")
formatter.numberStyle = .decimal. 

Output:

5 000 000

סטנלי גרונן
  • 2,917
  • 23
  • 46
  • 68
Moin
  • 35
  • 1
  • 5
0

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) ?? ""
    }
}
  • 1
    You should set the locale before setting the other properties. Btw if you set the locale fixed to "en_US" there is no need to set the currencyGroupingSeparator. – Leo Dabus May 26 '20 at 15:42
-4

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)

phrogg
  • 888
  • 1
  • 13
  • 28