I have UITextField with Decimal Pad and i want to convert it's value to float.
var myValue: Float = NSString(string: myTextField.text).floatValue
On my emulator i have no problems: in Decimal Pad i see numbers and "." so i can enter values like 123.45, but on device i have a problem because on decimal pad i see numbers and ",". So after adding "123,45" to myTextField i see that
myValue = 123
I know that i can change "." to "," in setting but i am really not sure about my app users.
So my problem is - how can i get float value from decimal pad not only with "." using Swift?
I see two kind of solutions:
1) how can i config decimal pad to show "." instead of "," on any device?
2) how can i convert to float strings with "," delimiter?
I have this snippet only in ObjC, but the answer is that you need to use an NSNumberFormatter, the problem is due to a difference in how locale is managed from the input to the inner float representation.
numberformatter = [[NSNumberFormatter alloc] init];
[numberformatter setNumberStyle:NSNumberFormatterDecimalStyle];
[numberformatter setMaximumFractionDigits:2];
[numberformatter setMinimumFractionDigits:0];
[numberformatter setLocale:[NSLocale currentLocale]];
Here more hints on how to use number formatters
Related
So right now I have the following code:
- (NSString*)convertToLocalCurrencyFormat:(NSDecimalNumber*)result {
NSNumberFormatter* formatter = [[NSNumberFormatter alloc] init];
formatter.numberStyle = NSNumberFormatterCurrencyStyle;
formatter.currencyCode = self.comparisonCurrency;
formatter.usesSignificantDigits = YES;
return [formatter stringFromNumber:result];
}
When I pass in an NSDecimalNumber* containing 678071967196719797153475347466.94627863, it gets formatted to ¥678,072,000,000,000,000,000,000,000,000 (with the currencyCode set to JPY). If I leave out the formatter.usesSignificantDigits = YES line, then it gets formatted to ¥678,071,967,196,719,797,153,475,347,467, closer, but still dropping the decimal and following values.
However, when I pass in 6780.0416000000012517376, it's formatted correctly to ¥6,780.04 with the significant digits line. It gets formatted to ¥6,780 without the significant digits line.
I know that NSNumberFormatter can take in any NSNumber as a parameter, but can only deal with values as precise as doubles, leaving NSDecimalNumber with no errors and incorrect results.
How can I format NSDecimalNumbers with currency codes without loss of precision?
Thanks
Try setting the minimum fraction digits instead:
formatter.minimumFractionDigits = 2;
HTH
Is there anyway in objective-c to determine if a currency uses a decimal point (regardless of declared NSNumber type)?
I have multiple locales and I use NSNumberFormatter (based on locale) to set string currency string style, however before-hand I would like to know if the selected locale currency uses a decimal point.
[_cf setLocale:
[NSLocale localeWithLocaleIndentifier:[NSString stringWithFormat:#"%#",locale]]]];
[cf setNumberStyle:NSNUmberFormatterCurrencyStyle];
NSString *value = [cf stringFromNumber:price];
return value;
After creating the NSNumberFormatter with currency style, ask the formatter how many fraction digits it has.
NSInteger maxFractionDigits = cf.maximumFractionDigits;
if (maxFractionDigits == 0) {
// this currency is an integer, not a decimal
}
One example where this is true is the Japanese Yen (¥).
I would to round a decimal number like this :
4363,65 ----> 4364
I have tried this :
NSDecimalNumber *decimalNumber = [NSDecimalNumber decimalNumberWithString#"4363,65"];
NSDecimalNumberHandler *behav = [[NSDecimalNumberHandler alloc] initWithRoundingMode:NSRoundPlain scale:NSDecimalNoScale
raiseOnExactness:YES
raiseOnOverflow:YES
raiseOnUnderflow:YES
raiseOnDivideByZero:YES];
NSDecimalNumber *roundedDecimal = [decimalNumber decimalNumberByRoundingAccordingToBehavior:behav];
I don't have the expected result.How i can round it ?
I see 2 problems in your code. The first is the creation of the number. You are using , as a decimal separator. If your locale is not configured to use , for decimals, your number will be parsed as 4363. This is what probably happens.
The second problem is the value for the scale parameter. It takes the number of decimal digits but you are using a constant NSDecimalNoScale which is actually equal to SHRT_MAX. That's not what you want.
//make sure you use the correct format depending on your locale
NSDecimalNumber *decimalNumber = [NSDecimalNumber decimalNumberWithString:#"4363.65"];
NSDecimalNumberHandler *behav = [[NSDecimalNumberHandler alloc] initWithRoundingMode:NSRoundPlain
scale:0
raiseOnExactness:YES
raiseOnOverflow:YES
raiseOnUnderflow:YES
raiseOnDivideByZero:YES];
This is the easiest way:
float f = 4363,65;
int rounded = (f + 0.5);
In Swift, how would you create an NSNumberFormatter that would preserve trailing zeros after a decimal (12.000) while also generating a number appropriate for the current locale?
My current code and example output:
let formatter = NSNumberFormatter()
formatter.numberStyle = .DecimalStyle
formatter.locale = NSLocale.currentLocale()
formatter.maximumFractionDigits = 10
var doubleNumString = "12.0"
println(formatter.numberFromString(doubleNumString)) //in English it prints 12, want it to print 12.0
var doubleNumString = "12.000"
println(formatter.numberFromString(doubleNumString)) //prints 12, want it to print 12.000
var doubleNumString = "12.125"
println(formatter.numberFromString(doubleNumString)) //prints 12.125 as expected
var doubleNumString = "1234"
println(formatter.numberFromString(doubleNumString)) //prints 1,234 as expected
I've already coded it such that if the string ends in a decimal ("12.") then it won't use this formatter to generate the number and will instead just display the number then the decimal (but I will need to improve that because some languages read right to left).
One solution would be to check if the string contains a period and if so, check if all digits that follow it are 0, and if so then don't run it through the number formatter and instead run only the int value through the formatter then append/prepend the decimal followed by the appropriate number of 0's.
Is there a better/cleaner solution?
As mentioned by Martin R, you can set the minimumFractionDigits and maximumFractionDigits to the same number which will enforce that many fraction digits always be displayed. To know how many to display you need to take a substring after the decimal to the end and count its elements. To know whether or not all of the fraction digits are 0's, I created a helper method that converts that substring to a number and if it equals 0 then you know they were all 0's.
Unfortunately you need to convert the string to a localized number using a couple different NSNumberFormatters based on the original string number. So if it does contain a decimal and everything after it is a 0 then you need to create a different formatter, convert the string to a number, then convert that number to a string in order to display it respecting the user's locale. Otherwise you can just use your original number formatter.
This function takes care of your requirement. pass same for & from locale (e.g. en_US)
+ (NSString*) stringForString:(NSString*) string forLocale:(NSString*) toLocaleCode fromLocal:(NSString*) fromLocaleCode {
NSLocale *fromLocale = [[NSLocale alloc] initWithLocaleIdentifier:fromLocaleCode];
NSNumberFormatter *sourceFormatter = [[NSNumberFormatter alloc] init];
[sourceFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
[sourceFormatter setUsesGroupingSeparator:NO];
[sourceFormatter setLocale:fromLocale];
NSNumber *localizedNumber = [sourceFormatter numberFromString:string];
if (!localizedNumber) {
return string;
}
NSLocale *toLocale = [[NSLocale alloc] initWithLocaleIdentifier:toLocaleCode];
NSNumberFormatter *destinationFormatter = [[NSNumberFormatter alloc] init];
[destinationFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
[destinationFormatter setUsesGroupingSeparator:NO];
[destinationFormatter setLocale:toLocale];
NSString *localizedString = [destinationFormatter stringFromNumber:localizedNumber];
//add the zeros which were dropped because of the sourceDecimalString number conversion e.g. 0.20 is converted to 0.2
if (localizedString.length < string.length) {
NSRange rangeOfDecimal = [string rangeOfString:sourceFormatter.decimalSeparator];
if (rangeOfDecimal.location != NSNotFound) {
NSString* sourceDecimalString = [string substringFromIndex:rangeOfDecimal.location];
rangeOfDecimal = [localizedString rangeOfString:destinationFormatter.decimalSeparator];
if (rangeOfDecimal.location != NSNotFound) {
NSString* destinationDecimalString = [localizedString substringFromIndex:rangeOfDecimal.location];
if (destinationDecimalString.length < sourceDecimalString.length) {
int difference = sourceDecimalString.length - destinationDecimalString.length;
int toalDecimalDigits = (destinationDecimalString.length - 1) + difference; //-1 to remove '.'
destinationFormatter.minimumFractionDigits = toalDecimalDigits;
destinationFormatter.maximumFractionDigits = toalDecimalDigits;
localizedString = [destinationFormatter stringFromNumber:localizedNumber];
}
}
else{//this indicates no decimal separator in the return string
int toalDecimalDigits = (sourceDecimalString.length - 1); //-1 to remove '.'
destinationFormatter.minimumFractionDigits = toalDecimalDigits;
destinationFormatter.maximumFractionDigits = toalDecimalDigits;
localizedString = [destinationFormatter stringFromNumber:localizedNumber];
}
}
}
return localizedString;
}
I would like to have a currency input field in my app where the user can either include the currency symbol (as appropriate for their locale), or not, as they please.
I have a text field set up and I am storing the value in a NSDecimalNumber (which I understand is the recommended way to store currency).
The following code will get me from an NSDecimalNumber to a formatted currency string:
[NSNumberFormatter localizedStringFromNumber:currencyValue numberStyle:NSNumberFormatterCurrencyStyle]
But I can't find a way to do the reverse of that. i.e., take the string that the user has typed into my text field and convert it (if possible) into an NSDecimalNumber. Keeping in mind that the currency symbol may be there (because it came from the function above) or not (because the user didn't bother to type the currency symbol).
What am I missing?
If I can't figure this out I will just not accept any currency symbol at all (i.e., just parse it using the code below). But it seems better to allow the currency symbol.
[NSDecimalNumber decimalNumberWithString:currencyString locale:[NSLocale currentLocale]]
I have the feeling I am missing something. What's the right way to convert back and forth between a localized currency string and an NSDecimalNumber?
If you get an instance of an NSNumberFormatter (instead of using the static method call) you can use the NSNumberFormatter's "stringFromNumber" method to format the currency string and use "numberFromString" to parse that string back into a number.
https://developer.apple.com/library/mac/documentation/cocoa/reference/foundation/Classes/NSNumberFormatter_Class/Reference/Reference.html
If you are sure that the currency symbol, if it exists, will be at the beginning of the string, then you can just use this (string is the NSString that the user enters and number is the NSDecimalNumber that represents the value of the currency)
NSDecimalNumber *number;
if([string hasPrefix:#"0"] || [string hasPrefix:#"1"] || [string hasPrefix:#"2"] || [string hasPrefix:#"3"] || [string hasPrefix:#"4"] || [string hasPrefix:#"5"] || [string hasPrefix:#"6"] || [string hasPrefix:#"7"] || [string hasPrefix:#"8"] || [string hasPrefix:#"9"]) {
// The string does not contain a currency symbol in the beginning so we can just assign that to a NSDecimalNumber
number = [NSDecimalNumber decimalNumberWithString:string];
}
else {
// The string contains a currency symbol at the beginning and we will assign the currency symbol to the currencySymbol variable
NSString *currencySymbol;
currencySymbol = [string substringWithRange:NSMakeRange(0,1)];
number = [NSDecimalNumber decimalNumberWithString:[string stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:#""];
}
This should do the trick:
NSNumberFormatter *currencyFormatter = [[NSNumberFormatter alloc] init];
[currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
[currencyFormatter setLenient:YES];
NSString* input = #"$3,456.78";
NSNumber *number = [currencyFormatter numberFromString:input];
NSDecimalNumber *price = [NSDecimalNumber decimalNumberWithDecimal:[number decimalValue]];