80

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.

7 Answers 7

190

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(with: " ", 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}"
Sign up to request clarification or add additional context in comments.

4 Comments

dont set the separator, let the formatter choose one depending on locale.
@Sulthan no locale will give him a half width space
Can u help me to add this to textField, how to make this ? when we typing in textfield numbers should changing (adding spaces after thousand)
@Аба-БакриИбрагимов stackoverflow.com/a/34294660/2303865
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"

4 Comments

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 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.
@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.
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.
26

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")

Comments

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"

1 Comment

I used self instead of hashValue.
2

Code:

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

Output:

5 000 000

Comments

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 Comment

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.
-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)

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.