Please can you tell me why my NSNumberFormatter is only letting me use 4 digits (i.e £2,222) instead of infinite digits?
- (BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSString *input = [textField.text stringByAppendingString:string];
[textField setText:[self numberFormattedString:input]];
return NO;
}
- (NSString *) numberFormattedString:(NSString *)str {
str = [str stringByReplacingOccurrencesOfString:#"£" withString:#""];
NSNumberFormatter *formatter = [[[NSNumberFormatter alloc] init] autorelease];
[formatter setNumberStyle:NSNumberFormatterCurrencyStyle];
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en-UK"];
[formatter setLocale:locale];
[locale release];
[formatter setMaximumFractionDigits:3];
[formatter setMinimumFractionDigits:0];
return [formatter stringFromNumber:[NSNumber numberWithFloat:[str floatValue]]];
}
Edit--
When I type a fifth digit, having already 4 digits inside the UITextField, the textField's text is reset back to fifth digit typed alone.
E.G
I enter 1000 into the UITextField, I then enter a further digit of 5. As 5 is the fifth digit, the UITextField's text gets reset to the fifth digit alone. The UITextField now displays '5'.
TIA.
XcodeDev
The problem is that a comma is breaking [NSString floatValue]. When you get to entering the fifth digit, str ends up looking something like 1,0005, which floatValue converts to a value of 1 since it doesn't know how to deal with the comma and/or the fact that there are too many digits after it. Add this code
str = [str stringByReplacingOccurrencesOfString:#"," withString:#""];
as the first or second line of numberFormattedString and it will work.
What's probably happening is that as the user types, the formatter is inserting commas at the thousand marks. You aren't stripping those out when you do the reformatting like you are with the pound sign, so at some point the formatting function is being given a string like "1,000".
When you try to get the floatValue of that to convert it back into an NSNumber for reformatting, floatValue returns 1 because it can't parse commas.
Solution: add this extra line to your formatting function:
str = [str stringByReplacingOccurrencesOfString:#"," withString:#""];
Related
I have an issue with the textfield. This case works fine with the english language. However, if the device language is change to french (canada) , the textfield is not showing the values after the decimal.
For english:
I enter 99.99 and click Done. The text field display 99.99
For french:
I enter 99,99 and click Done . The text field display 99,00
Here is my code:
_amountField.text = [_amountField currencyFormatFromValue:[NSNumber numberWithDouble:_amountField.text.doubleValue]];
Here the [NSNumber numberWithDouble:_amountField.text.doubleValue] part is returning 99.99 in case of english and 99,00 in case of french
-(NSString *)currencyFormatFromValue:(NSNumber *)value{
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
formatter.positiveFormat = #"###.00";
formatter.roundingMode = NSNumberFormatterRoundFloor;
[formatter setNumberStyle:NSNumberFormatterCurrencyStyle];
NSString *groupingSeparator = [[NSLocale currentLocale] objectForKey:NSLocaleGroupingSeparator];
[formatter setGroupingSeparator:groupingSeparator];
[formatter setUsesGroupingSeparator:YES];
[formatter setCurrencySymbol:#""];
[formatter setMinimumIntegerDigits:1];
NSString *formattedValue = [formatter stringFromNumber:value];
return formattedValue;
}
I am not sure, why the french text which is converted in double is terminating the decimal values. Any ideas?
Do I need to convert the text back to english before I sent the value to formatter?
I think your positiveFormat specification with the period is conflicting with NSNumberFormatterCurrencyStyle. I would try commenting out a bunch of lines and recompiling:
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
// formatter.positiveFormat = #"###.00";
// formatter.roundingMode = NSNumberFormatterRoundFloor;
[formatter setNumberStyle:NSNumberFormatterCurrencyStyle];
// NSString *groupingSeparator = [[NSLocale currentLocale] objectForKey:NSLocaleGroupingSeparator];
// [formatter setGroupingSeparator:groupingSeparator];
// [formatter setUsesGroupingSeparator:YES];
// [formatter setCurrencySymbol:#""];
// [formatter setMinimumIntegerDigits:1];
NSString *formattedValue = [formatter stringFromNumber:value];
return formattedValue;
In my experience, the formatting out of the box will include grouping separator, currency symbols, rounding mode, etc. Specifying it again can potentially confuse the formatter.
If you really need to explicitly specify the positive format, you can try building the positive format string using the NSLocaleDecimalSeparator constant so that it will be a period or comma as required:
NSString *decimalSeparator = [[NSLocale currentLocale] objectForKey:NSLocaleDecimalSeparator];
formatter.positiveFormat = [NSString stringWithFormat:#"###%#00", decimalSeparator];
But I don't recommend it!
I found a way to make it work. I need to remove the , character in case of french that occur in the text field and send to formatter .
_amountField.text = [_amountField currencyFormatFromValue:[NSNumber numberWithDouble:[_amountField.text strippedAmount]doubleValue]];
and
//macro
#define IsFrenchLanguage() ([[[NSLocale preferredLanguages] objectAtIndex:0] rangeOfString:#"fr"].location != NSNotFound)
-(NSString *) strippedAmountString
{
NSString * thousandsSeparator = IsFrenchLanguage() ? #" " : #",";
return [self.amountField.text stringByReplacingOccurrencesOfString:thousandsSeparator withString:#""];
}
I need to achieve this:
When user types (on a textField): 123456
the field will show 123,456
I have the code below, but, for some reason I can figure it out when I type "5" the whole field is reseted to 1.
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
NSString *textt = [textField.text stringByReplacingCharactersInRange:range withString:string];
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
NSString *formattedString = [formatter stringFromNumber:[NSNumber numberWithFloat:[textt floatValue]]];
textField.text = formattedString;
return NO;
}
it does the job for you, shame on me I could have done it better, but I hope someone can give you a more elegant solution for this issue. (e.g. using regexp or something)
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
NSNumberFormatter *_formatter = [[NSNumberFormatter alloc] init];
[_formatter setNumberStyle:NSNumberFormatterDecimalStyle];
NSMutableString *_pureNumber = [NSMutableString stringWithString:[textField.text stringByReplacingCharactersInRange:range withString:string]];
[_pureNumber replaceOccurrencesOfString:_formatter.groupingSeparator withString:#"" options:NSCaseInsensitiveSearch range:NSMakeRange(0, _pureNumber.length)];
[textField setText:[_formatter stringFromNumber:#([_pureNumber doubleValue])]];
return NO;
}
so, the general idea is you need to convert back your textt to a number.
the auto-parser cannot do it for you, becasue the after 1,234 the 1,2345 is not a valid number in this formatter, that is why you have got the very first number only, simply the parser chucks everything after the comma , away. (that is a groupingSeparator in this formatter).
For example, I have the following code, where lblPercent is an NSTextField:
double Progress = progress( Points);
[lblPercent setIntValue:(Progress)];
I set it as integer value so it tosses out the decimal, since for some reason the NSProgressIndicator forces me to use a double. Anyway, in the label adjacent to the progress bar, I want it see the number x% with the percent sign next to it.
I tried standard concatenation techniques but no dice.
You should use an NSNumberFormatter with the percent style
NSNumberFormatter* formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle: NSNumberFormatterPercentStyle];
// Any other format settings you want
NSString* formattedNumber = [formatter stringFromNumber: [NSNumber numberWithDouble: progress]];
try
[lblPercent setText:[NSString stringWithFormat:#"%d%%",[Progress intValue]]];
NSMutableString *value = lblPercent.text;
[value appendString:#"%"];
[lblPercent setText:value];
You can use unicode characters to get the percent sign.
i.e.
double value;
myLabel.text = [NSString stringWithFormat:#"%d\u0025", value ]
u0025 is the unicode character for 'percent sign'
NSInteger percentageProgress = (NSInteger) (Progress * 100);
[lblPercent setText:[NSString stringWithFormat:#"%d%%", percentageProgress]];
NSString *string = [NSString stringWithFormat:#"%.0f%#",Progress, #"%"];
[lblPercent setStringValue:string];
This seems to had worked for me doing it the way I had done it...
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
if (string.length == 0) {
return YES;
}
[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber* candidateNumber;
NSString* candidateString = [textField.text stringByReplacingCharactersInRange:range withString:string];
range = NSMakeRange(0, [candidateString length]);
[numberFormatter getObjectValue:&candidateNumber forString:candidateString range:&range error:nil];
if (([candidateString length] > 0) && (candidateNumber == nil || range.length < [candidateString length])) {
return NO;
}
else
{
return YES;
}
Hi, with this code i can insert only decimal values in a textfield.
The decimal separator is a comma ","
How do I change it to a dot "." ?
Thanks
There is a little thing called Localization. Every language uses a different character as a decimal separator. Where English uses a decimal point, other languages use a comma (or other characters).
When you create a NSNumberFormatter it uses the system locale (NSLocale instance) to decide about the decimal separator (and grouping separator and other things).
If you want a fixed behavior, then just set a different locale using [NSNumberFormatter setLocale:]
Also note there is one special kind of locale
[[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"] which defines a special locale which cannot be changed by user settings and is always the same.
In this case, using a NSNumberFormatter is not the best idea. This is one of the cases when you want to use a regular expression.
This may be a easy question but i am not able to find the logic.
I am getting the values like this
12.010000
12.526000
12.000000
12.500000
If i get the value 12.010000 I have to display 12.01
If i get the value 12.526000 I have to display 12.526
If i get the value 12.000000 I have to display 12
If i get the value 12.500000 I have to display 12.5
Can any one help me out please
Thank You
Try this :
[NSString stringWithFormat:#"%g", 12.010000]
[NSString stringWithFormat:#"%g", 12.526000]
[NSString stringWithFormat:#"%g", 12.000000]
[NSString stringWithFormat:#"%g", 12.500000]
float roundedValue = 45.964;
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setMaximumFractionDigits:2];
[formatter setRoundingMode: NSNumberFormatterRoundUp];
NSString *numberString = [formatter stringFromNumber:[NSNumber numberWithFloat:roundedValue]];
NSLog(numberString);
[formatter release];
Some modification you may need-
// You can specify that how many floating digit you want as below
[formatter setMaximumFractionDigits:4];//2];
// You can also round down by changing this line
[formatter setRoundingMode: NSNumberFormatterRoundDown];//NSNumberFormatterRoundUp];
Reference: A query on StackOverFlow
Obviously taskinoor's solution is the best, but you mentioned you couldn't find the logic to solve it... so here's the logic. You basically loop through the characters in reverse order looking for either a non-zero or period character, and then create a substring based on where you find either character.
-(NSString*)chopEndingZeros:(NSString*)string {
NSString* chopped = nil;
NSInteger i;
for (i=[string length]-1; i>=0; i--) {
NSString* a = [string substringWithRange:NSMakeRange(i, 1)];
if ([a isEqualToString:#"."]) {
chopped = [string substringToIndex:i];
break;
} else if (![a isEqualToString:#"0"]) {
chopped = [string substringToIndex:i+1];
break;
}
}
return chopped;
}