iOS: formatting decimal numbers

iphone, objective-c

Solution

I had the same problem. I was told that `NSNumberFormatter` converts everything to a `double` first. How did I solve it? It's easy, just write your own formatter.

- First round the decimal to 2 decimal digits.

- Get its description as a string.

- Find decimal point (.) in the string and replace it with the one you want.

- After every three digits from the decimal point to the left, insert a grouping separator.

Problem

I have an `NSDecimalNumber` representing a money amount. I want to print it as "999 999 999 999 999 999,00", regardless on the locale. How do I do that? NSNumberFormatter prints me 1 000 000 000 000 000 000,00 instead (it seems Apple engineers never designed the iPhone to be a platform for financial software). `[NSDecimalNumber description]` and `[NSDecimalNumber descriptionWithLocale]` both print correct value. How can I format the result, with grouping separator set to `@"\u2006"`, decimal separator to `@"**,**"`, and exactly 2 decimal digits after the decimal seperator? Thanks in advance! Update: Here's my solution, 10x to Sulthan: ``` @implementation NSDecimalNumber(MiscUtils) -(NSString*)moneyToString { static NSDecimalNumberHandler* s_handler = nil; if( !s_handler ) s_handler = [ [ NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundPlain scale:2 raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:NO ] retain ]; NSDecimalNumber *dec = [ self decimalNumberByRoundingAccordingToBehavior:s_handler ]; NSString* str = [ dec description ]; NSRange rDot = [ str rangeOfString:@"." ]; int nIntDigits = str.length; int nFracDigits = 0; if( rDot.length > 0 ) { nIntDigits = rDot.location; nFracDigits = str.length - ( rDot.location + 1 ); } int nGroupSeparators = ( nIntDigits - 1 ) / 3; NSMutableString* res = [ NSMutableString stringWithCapacity:nIntDigits + nGroupSeparators + 3 ]; NSString *groupingSeparator = @"\u2006"; int nFirstGroup = ( nIntDigits % 3 ); int nextInd = 0; if( nFirstGroup ) { [ res appendString:[ str substringToIndex:nFirstGroup ] ]; nextInd = nFirstGroup; } while( nextInd < nIntDigits ) { if( res.length > 0 ) [ res appendString:groupingSeparator ]; [ res appendString:[ str substringWithRange:NSMakeRange( nextInd, 3 ) ] ]; nextInd += 3; } if( nFracDigits > 0 ) { if( nFracDigits > 2 ) nFracDigits = 2; [ res appendString:@"," ]; [ res appendString:[ str substringWithRange:NSMakeRange( rDot.location + 1, nFracDigits ) ] ]; while( nFracDigits < 2 ) { [ res appendString:@"0" ]; nFracDigits++; } } else [ res appendString:@",00" ]; // DLog( "formatDecimal: %@ -> %@", dec, res ); return res; } @end ```

Original source