The NSNumberFormatter is one of those useful Foundation classes that is easy to forget about. It has a simple purpose of allowing you to flexibly convert backwards and forwards between numbers (NSNumber) and localised string (NSString) representations of those numbers. This post is a collection of quick notes for some of the most common uses when converting a number to a string.
NSNumberFormatterStyle
If you have very simple requirements you can avoid having to allocate an NSNumberFormatter and use a class method localizedStringFromNumber:numberStyle:
with some predefined styles. The basic approach assuming we have an NSNumber initialised with the double value 1234567.8369
:
NSNumber *num1 = [NSNumber numberWithDouble:1234567.8369];
NSString *numberStr = [NSNumberFormatter localizedStringFromNumber:num1 numberStyle:style];
where style is an NSNumberFormatterStyle
constant. What follows is the output for each of the pre-defined styles assuming the English (en_GB) locale.
No Style
// No Style - NSNumberFormatterNoStyle
// 1234568
Decimal Style
Uses a grouping separator for thousands and three significant digits after the decimal separator:
// Decimal Style - NSNumberFormatterDecimalStyle
// 1,234,567.837
Currency style
Prefixes the currency symbol for the locale and uses two significant digits:
// Currency Style - NSNumberFormatterCurrencyStyle
// £1,234,567.84
Percent Style
The number is multiplied by 100 and shown with the percent symbol suffix:
// Percent Style - NSNumberFormatterPercentStyle
// 123,456,784%
Scientific Style
Shown in scientific notation:
// Scientific Style - NSNumberFormatterScientificStyle
// 1.2345678369E6
Spell Out Style
The number is spelt out in full for the current locale:
// Spell Out Style - NSNumberFormatterSpellOutStyle
// one million two hundred thirty-four thousand five hundred
// sixty-seven point eight three six nine
Locales
A big advantage of using the NSNumberFormatter is that it takes care of formatting the output based on the user locale. So with the device locale set to Spanish the previous examples become:
// Style en_GB es_ES
// NSNumberFormatterNoStyle 1234568 1234568
// NSNumberFormatterDecimalStyle 1,234,567.837 1.234.567,837
// NSNumberFormatterCurrencyStyle £1,234,567.84 € 1.234.567,84
// NSNumberFormatterPercentStyle 123,456,784% 123.456.784%
// NSNumberFormatterScientificStyle 1.2345678369E6 1,2345678369E6
Note how the currency symbol changes and that the comma separator and decimal point are reversed. The spell out style in the Spanish locale gives the following:
// un millón doscientos treinta y cuatro mil quinientos
// sesenta y siete coma ocho tres seis nueve
Custom Formatters
When the predefined styles are not sufficient for your needs you can create a custom number formatter:
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
You can still set the basic number style using one of the predefined styles. So for a custom decimal number format you would start off with:
[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
There is a long list of properties for the number formatter that allow you to customise the output. So for example if I want to limit the displayed number to two decimal places and round the number down instead of up:
[numberFormatter setMaximumFractionDigits:2];
[numberFormatter setRoundingMode:NSNumberFormatterRoundDown];
When you want to obtain the NSString
representation of the number you use stringFromNumber:
passing the NSNumber
as the argument:
// 1,234,567.83
NSString *text = [numberFormatter stringFromNumber:num1];
For fine grained control you can set a format string for both positive and negative numbers. So if I wanted negative numbers to be displayed in brackets instead of with a negative symbol:
NSNumber *num2 = [NSNumber numberWithDouble:-55.28];
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
[numberFormatter setNegativeFormat:@"(0.00)"];
// (55.28)
NSString *text = [numberFormatter stringFromNumber:num2];
The syntax for the format string is defined by Unicode Technical Standard 35 and is a little cryptic. The pattern consists of a prefix, numeric part and a suffix. The prefix and suffix allow you to specify currency and percentage symbols. The numeric part specifies separators (grouping and decimal) and the number of digits to use. To specify a number use either a #
or 0
depending on whether you want to zero pad or not. Some examples should make it clear:
// maximum 2 fractional digits with no padding
12.3456 using 0.## ==> 12.35
1.5 using 0.## ==> 1.5
// maximum 2 fractional digits with zero padding
12.3456 using 0.00 ==> 12.35
1.5 using 0.00 ==> 1.50
// thousands separator
1500 using #,##0.00 ==> 1,500.00
Note that the grouping separator (,
) and decimal separator (.
) are replaced by the locale equivalent in the output string.
Currency Symbols
A quick tip if you are using a format string to create a currency number format. When you want to specify the position of the currency symbol in the prefix or suffix of the format string you need to use the Unicode currency symbol ¤ (\u00A4). The easiest way I have found to get this character is to use the character viewer. From the Finder, select Show Special Characters...
from the Edit
menu. If the Unicode category is not already shown you will need to add it using the settings menu from within the character viewer:
Scroll down the list until you see the Code Tables group, open the group and select the Unicode category:
You then need to select the character with the code 00A4 from the table or type a4 into the search bar. With the currency sign symbol selected you can then add it to the favorites for easy access. Double click the character to insert it at the current cursor position.
To finish up here is an example of a custom currency format using the currency symbol:
NSNumberFormatter *currencyFormatter = [[NSNumberFormatter alloc] init];
[currencyFormatter setPositiveFormat:@"¤#,##0.00"];
[currencyFormatter setNegativeFormat:@"(¤0.00)"];
Using this number formatter would give the following results in the en_GB locale:
1.5 ==> £1.50
1500 ==> £1,500.00
-1.56789 ==> (£1.57)