NSNumberFormatter removing spaces before currency - ios

I am using NSNumberFormatter to format my numbers to strings.
I have a device with Hebrew (israel) region format (settings->General->International->Region Format).
When I try to format the number 100 for instance I get 100 $.
My goal is to remove the space before the currency sign and get just 100$

I ended up changing positiveSuffix and negativeSuffix properties
by removing the spaces from them
because my NSNumberFormatter is static in my application I set them to nil at the end of each use
static NSNumberFormatter *currencyFormatter;
if (!currencyFormatter) {
currencyFormatter = [[NSNumberFormatter alloc] init];
[currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
[currencyFormatter setNegativeFormat:#""];
}
// remove spaces at the suffix
currencyFormatter.positiveSuffix = [currencyFormatter.positiveSuffix stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
currencyFormatter.negativeSuffix = [currencyFormatter.negativeSuffix stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
// get the return number
NSString* retNum = [currencyFormatter stringFromNumber:val];
// this code is for the next time using currencyFormatter
currencyFormatter.positiveSuffix = nil;
currencyFormatter.negativeSuffix = nil;
return retNum;

How about just removing all spaces from the string before running it through NSNumberFormatter? (as answered in this question)
NSString *stringWithoutSpaces = [myString
stringByReplacingOccurrencesOfString:#" " withString:#""];

Related

Convert numbers to currency

I have number 36381129. I need number 36.381,129
I tried this code, but it doesn't work.
int number = 36381129;
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle: NSNumberFormatterCurrencyStyle];
NSString *numberAsString = [numberFormatter stringFromNumber: [NSNumber numberWithInt:number]];
I give this number.
36.381.129,00 $
I think this is BRAZILIAN REAL CURRENCY Format. You have to call this method with your price in float value, and this method returns your string into your format. Like if we pass 123456789, then it will return 123,456,789.00.
//Convert Price to Your Price Format
+(NSString*)convertFormat:(float)value{
NSString * convertedString = [NSString stringWithFormat:#"%.2f", value];
NSString * leftPart;
NSString * rightPart;
if (([convertedString rangeOfString:#"."].location != NSNotFound)) {
rightPart = [[convertedString componentsSeparatedByString:#"."] objectAtIndex:1];
leftPart = [[convertedString componentsSeparatedByString:#"."] objectAtIndex:0];
}
//NSLog(#"%d",[leftPart length]);
NSMutableString *mu = [NSMutableString stringWithString:leftPart];
if ([mu length] > 3) {
[mu insertString:#"." atIndex:[mu length] - 3];
//NSLog(#"String is %# and length is %d", mu, [mu length]);
}
for (int i=7; i<[mu length]; i=i+4) {
[mu insertString:#"." atIndex:[mu length] - i];
//NSLog(#"%d",mu.length);
}
convertedString = [[mu stringByAppendingString:#","] stringByAppendingString:rightPart];
return convertedString;
}
For more details, refer this blog.
Hope, this is what you're looking for. Any concern get back to me.
Welcome to SO. Your question is pretty vague.
Currency formats depend on the user's locale. It's generally better to either use the default locale of the device, or set a locale, and then let the currency formatter create that string that's appropriate for that locale.
If you set up a hard-coded currency format then it will be wrong for some users. (For example in the US we use a "." as a decimal separator and commas as a grouping symbol. In most of Europe they use a comma as a decimal separator and the period as a grouping symbol. Some countries put the currency symbol at the end of a currency amount, and others put it at the beginning.)
You can use this code:
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterCurrencyStyle];
NSString *groupingSeparator = [[NSLocale currentLocale] objectForKey:NSLocaleGroupingSeparator];
[formatter setGroupingSeparator:groupingSeparator];
[formatter setGroupingSize:3];
[formatter setAlwaysShowsDecimalSeparator:NO];
[formatter setUsesGroupingSeparator:YES];
and use it this way:
NSString *formattedString = [formatter stringFromNumber:[NSNumber numberWithFloat:rev];
This is a generic solution and will work for any country according to their grouping separator
Taken from: https://stackoverflow.com/a/5407103/2082569

NSString remove a non braking space

Let's say I get a string "123 4,56" from the following code (I have a Russian local at the moment which has comma as a default separator rather than a dot), how do I remove the space from it which in reality is a non breaking space and the standard code like [str stringByReplacingOccurrencesOfString:#" " withString:#""]; will not work:
NSString* amount = #"1234.56";
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:#"en_UK"]];
NSNumber *num = [formatter numberFromString:amount];
NSString* str = [NSString localizedStringWithFormat:#"%.2F", [num doubleValue]];
NSLog(#"Str Value: %#", str);
NSString *newStr = [str stringByReplacingOccurrencesOfString:#" " withString:#""];
NSLog(#"New Str Value: %#", newStr);
The output I get is:
Str Value: 1 234,56
New Str Value: 1 234,56
The problem I'm trying to solve is I get a string from the server which is a currency (i.e. 123.45) and I need to display that in the UITextField. The problem is that I can't just display the value as it comes from the server because it is dependant on the user local. If the user has a UK local that works fine, however if the user has a Russian local I need to display a comma instead of a dot, thus basically what the code above does. The issue I however get is that after converting the string from one local to another there is an annoying space added to it that I'm trying to get rid of.
Solution based on Doro answer
[str stringByReplacingOccurrencesOfString:#"\u00a0" withString:#""];
It sounds strange, did you check that that was exactly whitespace character?
i can offer this snippet for striping input characters using scanner:
- (NSString*) stripInputValue: (NSString*) inputValue
{
NSMutableString *strippedString = [NSMutableString
stringWithCapacity:inputValue.length];
NSScanner *scanner = [NSScanner scannerWithString:inputValue];
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setLocale:[NSLocale currentLocale]];
NSString *decimalSymbol = [formatter decimalSeparator];
NSCharacterSet *validCharacters = [NSCharacterSet characterSetWithCharactersInString:[#"1234567890" stringByAppendingString:decimalSymbol]];
while ([scanner isAtEnd] == NO) {
NSString *buffer;
if ([scanner scanCharactersFromSet:validCharacters intoString:&buffer]) {
[strippedString appendString:buffer];
} else {
[scanner setScanLocation:([scanner scanLocation] + 1)];
}
}
return strippedString;
}
Be careful - if you want to support multiply locales - some locales uses '.' as separator, some ','. You can check this programmatically, if needed.
EDIT
Also please note that iOS doesn't use a space as a separator but a non-breaking space (U+00A0) for localizedStringWithFormat: so that is your problem.
Hope this helps.
The first line should have worked
NSString* newStr = [str stringByReplacingOccurrencesOfString:#" " withString:#""];
But just in case it didn't, I have another way for you:
NSString* newStr2 = [[str componentsSeparatedByString:#" "] componentsJoinedByString:#""];
UPDATE:
Instead of playing with the locale manually, you should use dynamic locale method for your requirement.
Replace: [formatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:#"en_UK"]];
By:
[formatter setNumberStyle:NSNumberFormatterCurrencyStyle];
[formatter setLocale:[NSLocale currentLocale]];

Converting NSString number to float

I am having difficulties converting NSString's that have numbers into floats or something more useful.
I have tried the following code:
NSString *mystring = #"123"
int currentBidAmount = [myString integerValue];
No problem there.
Then float
NSString *mystring = #"123.95"
float currentBidAmount = [myString floatValue];
Again, no problem
However when myString has three decimals - I get an inaccurate number. For Example:
NSString *mystring = #"1.123.95"
float currentBidAmount = [myString floatValue];
It prints out: 1
Can someone tell me what I am doing wrong here?
The goal is to have two NSStrings - get their values and add them up for a total amount. So I need more accuracy than just I am getting now.
While you can get an NSString integer or floatValue you should use NSNumberFormatterfor that. Why? The decimal and grouping separator varies between countries and the floatValue code does only account for . as decimal separator. So users with a locale using a , are doomed.
How to:
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
float myFloat = [numberFormatter numberFromString:myString].floatValue;
Read up on various settings here: https://developer.apple.com/library/ios/documentation/cocoa/reference/foundation/classes/NSNumberFormatter_Class/Reference/Reference.html
you can't put two commas for a float value
this code works fins:
NSString *example = #"13124.4153";
float floatValue = [example floatValue];
NSLog(#"value = %f", floatValue);
Thanks for the help guys. I managed to solve the problem. The issue was the grouping separator. It separated by leaving a space. So this is why I had inaccurate numbers. Now, since I needed all my numbers to stay in this format but change when I was doing calculations (Adding sums together - I wrote a class method that looks like this:
(NSString *)getDisplayAmountStringWithValue: (NSString *)value Currency: (NSString *)currency
{
NSDecimalNumber *decimalValue = [NSDecimalNumber decimalNumberWithString:[value stringByReplacingOccurrencesOfString:#"," withString:#""]];
if ([decimalValue isEqualToNumber:[NSDecimalNumber notANumber]]){
decimalValue = [NSDecimalNumber decimalNumberWithString:#"0"];
}
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
[formatter setGroupingSeparator:#" "];
[formatter setDecimalSeparator:#"."];
[formatter setMaximumFractionDigits:2];
[formatter setMinimumFractionDigits:2];
if ([currency length] > 0){
[formatter setPositivePrefix:[NSString stringWithFormat:#"%#", currency]];
[formatter setNegativePrefix:[NSString stringWithFormat:#"%#-", currency]];
}else {
[formatter setGroupingSeparator:#""];
}
NSString *newNumberString = [formatter stringFromNumber:decimalValue];
return newNumberString;
}
Notice the if statement. I simply remove the space if I don't supply a currency (Which is not needed when adding sums together) - this along with my existing code, works perfectly.
Thanks for all the tips.

Having trouble using NSNumberFormatter for currency conversion in iOS

I have a UITextField that receives numeric input from the user in my application. The values from this textfield then get converted into currency format using NSNumberFormatter within my shouldChangeCharactersInRange delegate method. When I enter the number "12345678", the number gets correctly converted to $123456.78 (the numbers are entered one digit at a time, and up to this point, everything works smoothly). However, when I enter another digit after this (e.g. 9), rather than displaying "1234567.89", the number "1234567.88" is displayed. If I enter another number after that, a totally different numbers after this (I'm using the number key pad in the application to enter the numbers. Here is the code that I have:
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterCurrencyStyle];
modifiedValue = [formatter stringFromNumber:[NSNumber numberWithFloat:[modifiedValue floatValue]]];
textField.text = modifiedValue;
The line that causes this unusual conversion is this one:
modifiedValue = [formatter stringFromNumber:[NSNumber numberWithFloat:[modifiedValue floatValue]]];
Can anyone see why this is?
It's likely to be a rounding error when doing the string->float conversion. You shouldn't use floats when dealing with currency. You could use a NSDecimalNumber instead.
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterCurrencyStyle];
// Below 2 lines if converting from a "currency" string
NSNumber *modifiedNumber = [formatter numberFromString:modifiedValue]; // To convert from the currency string to a number object
NSDecimalNumber *decimal = [NSDecimalNumber decimalNumberWithDecimal:[modifiedNumber decimalValue]];
// OR the below line if converting from a non-currency string
NSDecimalNumber *decimal = [NSDecimalNumber decimalNumberWithString:modifiedValue];
modifiedValue = [formatter stringFromNumber:decimal]; // Convert the new decimal back to a currency string
You may also consider making the number formatter lenient - often helps with user entered data.
[formatter setLenient:YES];
When I'm running number conversions to currency, I usually run this code:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString *text = _textField.text;
NSString *decimalSeperator = #".";
NSCharacterSet *charSet = nil;
NSString *numberChars = #"0123456789";
// the number formatter will only be instantiated once ...
static NSNumberFormatter *numberFormatter;
if (!numberFormatter)
{
[numberFormatter setLocale:[NSLocale currentLocale]];
numberFormatter = [[NSNumberFormatter alloc] init];
numberFormatter.numberStyle = NSNumberFormatterCurrencyStyle;
numberFormatter.maximumFractionDigits = 10;
numberFormatter.minimumFractionDigits = 0;
numberFormatter.decimalSeparator = decimalSeperator;
numberFormatter.usesGroupingSeparator = NO;
}
// create a character set of valid chars (numbers and optionally a decimal sign) ...
NSRange decimalRange = [text rangeOfString:decimalSeperator];
BOOL isDecimalNumber = (decimalRange.location != NSNotFound);
if (isDecimalNumber)
{
charSet = [NSCharacterSet characterSetWithCharactersInString:numberChars];
}
else
{
numberChars = [numberChars stringByAppendingString:decimalSeperator];
charSet = [NSCharacterSet characterSetWithCharactersInString:numberChars];
}
// remove amy characters from the string that are not a number or decimal sign ...
NSCharacterSet *invertedCharSet = [charSet invertedSet];
NSString *trimmedString = [string stringByTrimmingCharactersInSet:invertedCharSet];
text = [text stringByReplacingCharactersInRange:range withString:trimmedString];
// whenever a decimalSeperator is entered, we'll just update the textField.
// whenever other chars are entered, we'll calculate the new number and update the textField accordingly.
if ([string isEqualToString:decimalSeperator] == YES)
{
textField.text = text;
}
else
{
NSNumber *number = [numberFormatter numberFromString:text];
if (number == nil)
{
number = [NSNumber numberWithInt:0];
}
textField.text = isDecimalNumber ? text : [numberFormatter stringFromNumber:number];
}
return NO; // we return NO because we have manually edited the textField contents.
}
The link explaining this is Re-Apply currency formatting to a UITextField on a change event
Hope this works!

How to insert grouping comma in NSString as typed?

A user enters a numerical string in a UILabel and the text is displayed as the user types.
NSString *input = [[sender titleLabel] text];
[display_ setText:[[display_ text] stringByAppendingString:input]];
This works fine and I format the display using NSNumberFormatter so that if 1000000 is entered it is converted to 1,000,000 upon tapping another button.
However, I'd like to get those grouping commas to be displayed as the user types. I can understand how to insert things into strings, but how to do it as the user types is not clear to me. Would this require a mutable string?
Maybe somehow monitor the string length and split it into groups of three and make and display a new string with the commas inserted? I could probably do that, but it is the "as it is typed" part that has me stymied.
Another thought is to append and display the string, then read the display into a new NSString and format it and display it again right away. So I tried that, and it almost works:
if (userIsEntering)
{
NSNumberFormatter *fmtr = [[NSNumberFormatter alloc] init];
[fmtr setNumberStyle:NSNumberFormatterDecimalStyle];
[fmtr setGroupingSeparator:#","];
[fmtr setDecimalSeparator:#"."];
NSString *out = [[display_ text] stringByAppendingString:digit];
NSNumber *num = [fmtr numberFromString:out];
NSString* formattedResult = [fmtr stringFromNumber:num];
[display_ setText: [NSString stringWithFormat:#"%#", formattedResult]];
[fmtr release];
}
And, along with the fact that the formatter is created and released with every digit entered, after 4 digits it returns null.
UPDATE: I figured out how to do it in a label (with some help from #Michael-Frederick). It uses an NSNotification.
This works perfectly for non-decimal numbers, but when I try to enter a decimal point it is ignored and removed. If I do not invoke this method, the decimal point is accepted and all works well.
Numeric entry is as follows (from a button):
NSString *digit = [[sender titleLabel] text];
if (userIsStillWorking_)
{
[display_ setText:[[display_ text] stringByAppendingString:digit]];
}
else
{
[display_ setText: digit];
userIsStillWorking_ = YES;
}
[[NSNotificationCenter defaultCenter] postNotificationName:#"updateDisplay" object:nil];
And the updateDisplay method called by the notification is:
{
NSString *unformattedValue = [display_.text stringByReplacingOccurrencesOfString:
#"," withString:#""];
unformattedValue = [unformattedValue stringByReplacingOccurrencesOfString:
#"." withString:#""];
NSDecimalNumber *amount = [NSDecimalNumber decimalNumberWithString:unformattedValue];
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setGroupingSeparator:#","];
[formatter setDecimalSeparator:#"."];
[display_ setText: [ formatter stringFromNumber:amount]];
[formatter release];
}
I've tried commenting out
unformattedValue = [unformattedValue stringByReplacingOccurrencesOfString:
#"." withString:#""];
but that makes no difference.
EDIT:
A user cannot type into a uilabel. You need to use either a uitextfield or a uitextview.
If you want to use a uitextfield, do something like this...
- (void) viewDidLoad {
[super viewDidLoad];
[textField addTarget:self action:#selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
}
- (void) textFieldDidChange:(UITextField *)textField {
NSString *unformattedValue = [textField.text stringByReplacingOccurrencesOfString:#"," withString:#""];
unformattedValue = [unformattedValue stringByReplacingOccurrencesOfString:#"." withString:#""];
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
[formatter setGroupingSeparator:#","];
[formatter setDecimalSeparator:#"."];
NSNumber *amount = [NSNumber numberWithInteger:[unformattedValue intValue]];
textField.text = [formatter stringFromNumber:amount];
[formatter release];
}
Note that you are correct that NSNumberFormatter should be declared outside of the textFieldDidChange method. Note that this code would actually be for an integer. You could have to switch intValue to floatValue if need be. This code is untested, it is more of a general guide.
The best way to do this is to use 2 UIlabels. 1 of the labels is used to feed your NSNumberFormatter object by using [NSString stringByAppendingString:digit]; The other label is actually displayed. The trick is to set the label that is unformatted to hidden and the other label is set as an output for the number formatter. By feeding the hidden label to the number formatter, and outputting the displayed label from the number formatter, the number formatter should be set to the NSDecimalNumber style. Setting it all up this way, the result displayed is automatic commas while typing.

Resources