NSNumberFormatter trucates leading 0's - ios

I have written a function to convert a number from arabic numerals to digits. I have used NSNumberFormatterfor this. But the problem is the number caqn start with a zero and NSNumberFormatter truncates the leading zero. I need this value as I have to do a comparison. The number might not start with zero always. So I cannot put any other condition. Pleaes help me if anyone has a solution. Thank you.
My code is:
-(NSString*)convertNumberFromArabic:(NSString*)numberToConvert{
NSNumberFormatter *nf1 = [[NSNumberFormatter alloc] init];
NSLocale *locale = [NSLocale localeWithLocaleIdentifier:#"en"];
[nf1 setLocale:locale];
NSNumber *newNum = [nf1 numberFromString:numberToConvert];
NSString *reverseConvert = [nf1 stringFromNumber:newNum];
return reverseConvert;
}

Your question is a bit confusing. You say you want to "convert a number from arabic numerals to digits", but your method name says to Arabic. I have written the method to convert from Arabic to Latin. If you want to got the other way, you just change the YES to NO.
Here's the code:
-(NSString*)convertArabicDigitsToLatin:(NSString*)numberToConvert{
NSMutableString* result = [numberToConvert mutableCopy];
CFRange range = CFRangeMake(0, result.length);
CFStringTransform((__bridge CFMutableStringRef)result, &range, kCFStringTransformLatinArabic, YES);
return result;
}
This doesn't interpret the string as a number, it just transliterates the Arabic digits as string characters to Latin digits.

Related

NSNumberFormatter only formats up to 14 significant digits

I saw some code trying to format lat long using the following NSNumberFormatter.
NSNumberFormatter * sut = [[NSNumberFormatter alloc] init];
[sut setMaximumFractionDigits:20]; // also tried set to 15 or 16, not working too.
[sut setMaximumSignificantDigits:20];
NSLocale *enUSPOSIXLocale = [[NSLocale alloc]initWithLocaleIdentifier:#"en_US_POSIX"];
[sut setLocale:enUSPOSIXLocale];
NSString *expected = #"1.299129258067496"; // 16 significants digits
NSString *actual = [sut stringFromNumber:#(1.299129258067496)];
[[actual should] equal:expected];// Failed to pass, the actual is #"1.2991292580675"
Although in this case, we may not need to use the NSNumberFormatter to get the correct result, I'm wondering why NSNumberFormatter only returns string of up to 14 significant digits.
It only shows 14 decimal places because the double type rounds at 15 decimal places. This worked for me because you can set the number of decimal places shown.
[NSString stringWithFormat:#"%.20f", 1.299129258067496]
Just make sure the number of decimal places does not exceed the number otherwise the program makes up numbers to fill the rest. Hope this helps.

NSNumberFormatter numberFromString decimal number

I'm trying to parse a NSString with a NSNumberFormatter like following.
NSNumberFormatter *myFormatter = [[[NSNumberFormatter alloc] init];
NSNumber *myNumber = [myFormatter numberFromString:#"42.00000"];
numberFromString returns a NSNumber object in the simulator but not on a device.
The decimals (.00000) are causing the return value to be nil on a device because parsing 42 (without the decimals) works just fine (both in the simulator and on a device).
The reason I'm using a NSNumberFormatter is because is like how it returns nil if the string is not a valid number (which is working against me here :p). NSString doubleValue does not provide this kind of behaviour. Also, NSDecimalNumber decimalNumberWithString doesn't do the job because [NSDecimalNumber decimalNumberWithString:#"4a2.00000"] returns 4.
Any ideas why this would not work on a device?
Is it the locale? I tried setting myFormatter.numberStyle = NSNumberFormatterNoStyle and NSNumberFormatterDecimalStyle but it changes nothing.
As #rmaddy already said in a comment, the decimal separator of NSNumberFormatter is
locale dependent. If you have a fixed input format with the dot as decimal separator,
you can set the "POSIX locale":
NSNumberFormatter *myFormatter = [[NSNumberFormatter alloc] init];
[myFormatter setLocale:[NSLocale localeWithLocaleIdentifier:#"en_US_POSIX"]];
NSNumber *myNumber = [myFormatter numberFromString:#"42.00000"];
Alternatively, you can use NSScanner to parse a double value, as e.g. described
here: parsing NSString to Double
42.00000 is not a string mate, why not #"42.00000"?

how to convert india number to arabic number?

i'm trying to make calls from my app, but it seems i can't because the numbers are in india format (example : ٩٦٦٥٩٥٨٤٨٨٨٢) and to make it work , I have to convert this string to arabic format (example : 966595848882)
my code :
NSString *cleanedString = [[ContactInfo componentsSeparatedByCharactersInSet:[[NSCharacterSet characterSetWithCharactersInString:#"0123456789-+()"] invertedSet]] componentsJoinedByString:#""];
NSString *phoneNumber = [#"telprompt://" stringByAppendingString:cleanedString];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:phoneNumber]];
Use NSNumberFormatter with the appropriate locale. For example:
NSString *indianNumberString = #"٩٦٦٥٩٥٨٤٨٨٨٢";
NSNumberFormatter *nf1 = [[NSNumberFormatter alloc] init];
NSLocale *locale = [NSLocale localeWithLocaleIdentifier:#"hi_IN"];
[nf1 setLocale:locale];
NSNumber *newNum = [nf1 numberFromString:indianNumberString];
NSLog(#"new: %#", newNum);
This prints "966595848882".
I'm not 100% certain on the locale identifier above-- hi_IN should be "Hindi India". If that's not correct, use [NSLocale availableLocaleIdentifiers] to get a list of all known locale identifiers, and find one that's more appropriate.
Update: in order to pad this out to nine digits (or however many you want), convert back to an NSString using standard NSString formatting:
NSString *paddedString = [NSString stringWithFormat:#"%09ld", [newNum integerValue]];
The format %09ld will zero-pad out to nine digits.
It's also possible to do this using the same number formatter, converting the number above back into a string while requiring 9 digits. This also gives at least nine digits, with zero padding if necessary:
[nf1 setMinimumIntegerDigits:9];
NSString *reverseConvert = [nf1 stringFromNumber:newNum];

How to truncate an NSString 'x' characters after a certain character is found

Say I have an NSString, it represents a price that otherwise would be a double of course. I am trying to make it truncate the string at the hundredths place so it is something like 19.99 instead of 19.99412092414 for example. Is there a way, once detecting the decimal like so...
if ([price rangeOfString:#"."].location != NSNotFound)
{
// Decimal point exists, truncate string at the hundredths.
}
for me to cut off the string 2 characters after that ".", without separating it into an array then doing a max size truncate on the decimal before finally reassembling them?
Thank you very much in advance! :)
This is string manipulation, not math, so the resulting value won't be rounded:
NSRange range = [price rangeOfString:#"."];
if (range.location != NSNotFound) {
NSInteger index = MIN(range.location+2, price.length-1);
NSString *truncated = [price substringToIndex:index];
}
This is mostly string manipulation, tricking NSString into doing that math for us:
NSString *roundedPrice = [NSString stringWithFormat:#"%.02f", [price floatValue]];
Or you might consider keeping all numeric values as numbers, thinking of strings as just a way to present them to the user. For that, use NSNumberFormatter:
NSNumber *priceObject = // keep these sorts values as objects
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle: NSNumberFormatterCurrencyStyle];
NSString *presentMeToUser = [numberFormatter stringFromNumber:priceObject];
// you could also keep price as a float, "boxing" it at the end with:
// [NSNumber numberWithFloat:price];

How do I set a currency string value to a UITextField, preserving encoding?

I am developing an application in which I wish to handle different currency formats, depending on the current locale. Using a NSNumberFormatter I can correctly translate a number into string and back without problems.
But, if I put the string value into a UITextField and later get it back, I won't be able to convert the string back into a number and I will get a nil value instead.
Here is a sample code to explain the problem:
NSNumberFormatter *nf = [Utils currencyFormatter];
NSNumber *n = [NSNumber numberWithInt:10000];
NSString *s = [nf stringFromNumber:n];
NSLog(#"String value = %#", s);
UITextField *t = [[UITextField alloc] init];
// I put the string into the text field ...
t.text = s;
// ... and later I get the value back
s = t.text;
NSLog(#"Text field text = %#", s);
n = [nf numberFromString:s];
NSLog(#"Number value = %d", [n intValue]);
where the currencyFormatter method is defined this way:
+ (NSNumberFormatter *)currencyFormatter
{
static NSNumberFormatter *currencyFormatter;
if (!currencyFormatter) {
currencyFormatter = [[NSNumberFormatter alloc] init];
[currencyFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
[currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
[currencyFormatter setLocale:[NSLocale currentLocale]];
if ([currencyFormatter generatesDecimalNumbers] || [[currencyFormatter roundingIncrement] floatValue] < 1) {
[currencyFormatter setGeneratesDecimalNumbers:YES];
[currencyFormatter setRoundingIncrement:[NSNumber numberWithFloat:0.01]];
}
}
return currencyFormatter;
}
(The inner if is used to force the formatter to always round to the smallest decimal digit, eg. even for CHF values).
What I get in the Console is this:
2012-03-29 00:35:38.490 myMutuo2[45396:fb03] String value = € 10.000,00
2012-03-29 00:35:38.494 myMutuo2[45396:fb03] Text field text = € 10.000,00
2012-03-29 00:35:38.497 myMutuo2[45396:fb03] Number value = 0
The strange part is that the spacing character between € and 1 in the first line is represented in the console through a mid-air dot, while in the second line this dot disappears. I believe this is an encoding-related problem.
Can anyone help me solve this problem?
Thank you!
Edit
I changed my test code to this:
NSNumberFormatter *nf = [Utils currencyFormatter];
NSNumber *n = [NSNumber numberWithInt:10000];
NSString *s = [nf stringFromNumber:n];
NSLog(#"String value = %# (space code is %d)", s, [s characterAtIndex:1]);
UITextField *t = [[UITextField alloc] init];
t.text = s;
s = t.text;
NSLog(#"Text field text = %# (space code is %d)", s, [s characterAtIndex:1]);
n = [nf numberFromString:s];
NSLog(#"Number value = %d", [n intValue]);
to discover this:
2012-03-29 02:29:43.402 myMutuo2[45993:fb03] String value = € 10.000,00 (space code is 160)
2012-03-29 02:29:43.405 myMutuo2[45993:fb03] Text field text = € 10.000,00 (space code is 32)
2012-03-29 02:29:43.409 myMutuo2[45993:fb03] Number value = 0
The NSNumberFormatter writes down the space as a non-breaking space (ASCII char 160), and then the UITextField re-encodes that space as a simple space (ASCII char 32). Any known workaround for this behaviour? Perhaps I could just make a replacement of the space with a non-breaking space but ... will it work for all the locales?
A possible workaround: You could try to parse only the number values (and punctiation) via a regex pattern and create you currency value based on that number. If you do it in that way it is perhaps even more forgivable for the user, if he typed another currency symbol or other symbols that shouldnt be there...
I was able to solve this problem only extending the UITextField through a custom class. In this new class I put a new #property of type NSString in which I store the "computed" string value for the text field. This string will never be modified and will preserve the original encoding of the content of the text field.
When you need to work again on the original untouched content of the text field you have to refer to this new property instead of referring to the text property.
Using a separate string container is the only way to avoid these strange encoding changes.

Resources