wrong decimal separator with NSDecimalNumber in iOS - ios

I tried to output the description of a decimal number with the correct decimal separator in the following way:
NSString* strValue = #"9.94300";
NSDecimalNumber* decimalNumber = [NSDecimalNumber decimalNumberWithString: strValue];
NSLocale* locale = [NSLocale currentLocale];
NSLog(#"%#", [locale localeIdentifier]);
NSLog(#"%#", [decimalNumber descriptionWithLocale: locale] );
The output is:
de_DE
9.943
The decimal separator should be ',' instead of '.' for this locale. Where is the error? How can I output the correct decimal separator depending on the local?

#TriPhoenix: Yes I'm running iOS 5.
#Vignesh: Thank you very much. The following code works now if I set the iPhone language to German:
NSString* strValue = #"9.94300";
NSDecimalNumber* decimalNumber = [NSDecimalNumber decimalNumberWithString: strValue];
NSNumberFormatter* numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setFormatterBehavior: NSNumberFormatterBehavior10_4];
[numberFormatter setNumberStyle: NSNumberFormatterDecimalStyle];
NSLog(#"%#", [numberFormatter stringFromNumber: decimalNumber] );
The output is:
9,943
But now I have another problem. If I switch the iPhone language back to English the output is still 9,943 instead of 9.943. Do I make something wrong?

You can use this:
NSLocale *locale = [NSLocale currentLocale];
float r = 50/100;
NSString *str = [NSString stringWithFormat:#"%.2f%%", r];
str = [str stringByReplacingOccurrencesOfString:#"." withString:[locale objectForKey: NSLocaleDecimalSeparator]];
It worked!

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

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.

Get iOS current language (including country code)

I need to get a string like en_US or es_ES in iOS.
The obvious method is to use [NSLocale currentLocale] and get the language info from there. However, that gives you the "region format" and not the actual device language, which means that if you have the device language in english but the region format as "spain", it'll erroneously report es_ES.
If you need the device language you must do this instead:
[[NSLocale preferredLanguages] objectAtIndex:0]
However, that only gives you the language, so you get something like en or es, without the country code at the end.
How would I get the country code correctly, like Safari does?
Try with this code:
NSString *locale = [[NSLocale currentLocale] localeIdentifier];
NSRange startRange = [locale rangeOfString:#"_"];
NSString *result = [locale stringByReplacingCharactersInRange:NSMakeRange(0, startRange.length+1) withString:[[NSLocale preferredLanguages] objectAtIndex:0]];
DebugLog(#"current locale: %#", result);
Ok, seeing getting the right info out of iOS is probably not possible, here's a hackish solution but which gives the output I needed. It's not complete and it won't give precise output in some cases (like for arabic), but it's the best I've been able to get.
const string lang = [[[NSLocale preferredLanguages] objectAtIndex:0] UTF8String];
// Search the language with country code in the langs map
static std::map<string, string> langMap;
static bool initialized = false;
if(!initialized) {
#define LANG(l, c) langMap.insert(std::make_pair(#l, #c))
LANG(en, en-us); LANG(es, es-es); LANG(fr, fr-fr); LANG(de, de-de);
LANG(ja, ja-jp); LANG(nl, nl-nl); LANG(it, it-it); LANG(pt, pt-br);
LANG(da, da-dk); LANG(fi, fi-fi); LANG(nb, nb-no); LANG(sv, sv-se);
LANG(ko, ko-kr); LANG(ru, ru-ru); LANG(pl, pl-pl); LANG(tr, tr-tr);
LANG(uk, uk-ua); LANG(hr, hr-hr); LANG(cs, cs-cz); LANG(el, el-gr);
LANG(he, he-il); LANG(ro, ro-ro); LANG(sk, sk-sk); LANG(th, th-th);
LANG(ca, ca-es); LANG(hu, hu-hu); LANG(vi, vi-vn);
LANG(zh-Hans, zh-cn); LANG(pt-PT, pt-pt); LANG(id, id); LANG(ms, ms);
LANG(zh-Hant, zh-tw); LANG(en-GB, en-gb); LANG(ar, ar);
#undef LANG
initialized = true;
}
map<string,string>::iterator it = langMap.find(lang);
if( it != langMap.end() ){
return it->second;
}
// Didn't find a country code, default to the lang name
return lang;
Check the below code:
NSArray *langs = [NSLocale preferredLanguages];
for (NSString *lang in langs) {
NSLog(#"%#: %# %#",lang, [NSLocale canonicalLanguageIdentifierFromString:lang], [[[NSLocale alloc] initWithLocaleIdentifier:lang] displayNameForKey:NSLocaleIdentifier value:lang]);
}
Swift
NSLocale.preferredLanguages()[0] as String
Output would be like
en-GB
Source
An alternative would be to reconstruct the locale from the components of the current locale, swapping in the language that you want.
For example, to get the current locale but modified to use the language which UIKit is currently using to display the app:
let languageCode = Bundle.main.preferredLocalizations.first ?? "en"
var components = Locale.components(fromIdentifier: Locale.current.identifier)
components[NSLocale.Key.languageCode.rawValue] = languageCode
let locale = Locale(identifier: Locale.identifier(fromComponents: components))
I am using this at the moment. I have run a few test cases and it seems ok, However I am not convinced that it is a robust solution. I am surprised not to find a clear answer to this simple problem. I would not recommend my solution but I hope it can generate discussion.
NSLocale *locale = [NSLocale currentLocale];
NSString *countryCode = [locale objectForKey: NSLocaleCountryCode];
NSString *language = [[NSLocale preferredLanguages] firstObject];
NSString *myLocale = [NSString stringWithFormat:#"%#_%#",language,countryCode];
NSLocale *userLocale = [[NSLocale alloc] initWithLocaleIdentifier:myLocale];
NSDate* now = [NSDate date];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
NSString *dateFormat = [NSDateFormatter dateFormatFromTemplate:#"E MMM d yyyy HH:mm" options:0 locale:userLocale];
Simply do this:
NSString *language = [[NSLocale preferredLanguages] objectAtIndex:0];
NSString *locale = [[NSLocale currentLocale] objectForKey: NSLocaleCountryCode];
NSString *formattedStr = [NSString stringWithFormat:#"%#_%#",language, locale];
NSLog(#"%#", formattedStr); // Display en_US for example

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!

NSNumberFormatter removing spaces before currency

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:#""];

Resources