How to validate UITextfield in between 1 to 100 currency value accepted of maximum 2 decimal values.
Valid.
0.25 99.99, 1.99,100.00.
Other country currency decimal represent , also.
0,25
99,99
1,99
100,00
Invalid
00.25, 100.25, 0000000.00, 0.125, 9.567
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc]init];
numberFormatter.locale = [NSLocale currentLocale];// this ensures the right separator behavior
numberFormatter.numberStyle = NSNumberFormatterCurrencyStyle;
numberFormatter.usesGroupingSeparator = YES;
numberFormatter.usesSignificantDigits = YES;
numberFormatter.currencyGroupingSeparator = numberFormatter.locale.groupingSeparator;
numberFormatter.decimalSeparator = numberFormatter.locale.decimalSeparator;
NSString *expression = #"^([0-9]+)?(\\.,([0-9]{1,2})?)?$";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:expression
options:NSRegularExpressionCaseInsensitive error:nil];
NSUInteger numberOfMatches = [regex numberOfMatchesInString:newString
options:0 range:NSMakeRange(0, [newString length])];
if (numberOfMatches == 0)
return NO;
not working unable to press , inside UITextfield . sweden currency decimal represent "," not "." I want work calculation two entered value one is int another value is float
In the UItTxtfield delegate method try this code.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSInteger Currency = [textField.text integerValue];
if(Currency >= 100)
{
return NO;
}
else
{
NSString *enteredCurrency=textField.text;
if([enteredCurrency containsString:#"."])
{
NSArray *array=[enteredCurrency componentsSeparatedByString:#"."];
if([array[1] length] >= 2 || [array[0] length] >= 2)
{
return NO;
}
else
{
return YES;
}
}
else
{
return YES;
}
}
}
It's not recommended to implement this by yourlsef since its not scalable. You need to use NumberFormatter (or NSNumberFormatter for ObjC)
let formatter = NumberFormatter()
formatter.numberStyle = NumberFormatter.Style.currency
formatter.allowsFloats = false
formatter.maximumFractionDigits = 2 //you get to control how to present the price.
formatter.locale = locale //This should be the country Locale you need. for example: "en-us"
note that NSLocale gives you access to also grouping seperator and decimal separator, so you can check it later if you like.
formatter.currencyGroupingSeparator = locale.groupingSeparator
formatter.decimalSeparator = locale.decimalSeparator
Related
- (NSString *)_stringToFloat:(NSNumber *)number {
if (number && number > 0) {
return [NSString stringWithFormat:#"%.2f",[number floatValue]];
}
return #"0.0";
}
Using:
_lblAppointmentFee.text = [[NSString alloc]initWithFormat:#"%#",[self_stringToFloat:[_dicObject objectForKeyNotNull:#"rate"]]];
How can I can return "5.21" for a value of 5.21 and return "5" for a value of 5.00?
Use an NSNumberFormatter. Set the desired fraction digits.
NSNumberFormatter *nf = [[NSNumberFormatter alloc] init];
nf.numberStyle = NSNumberFormatterDecimalStyle;
nf.minimumFractionDigits = 0;
nf.maximumFractionDigits = 2;
NSString *result = [nf stringFromNumber:#(5.12)];
This gives a result of "5.12" while:
result = [nf stringFromNumber:#(5.00)];
gives a result of "5".
This also has the added bonus of properly formatting the result based on the user's locale.
I want to restrict UITextField to accept only one decimal point.
Also maximum 3 digits are allowed before decimal point & maximum 2 digits allowed after decimal point.
Please note that minimum digits can be 1 and decimal cant be entered a first.
How can I achieve it?
You can use below code for the same scenario.
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString *expression = #"^([0-9]*)(\\.([0-9]+)?)?$";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:expression options:NSRegularExpressionCaseInsensitive error:nil];
NSUInteger noOfMatches = [regex numberOfMatchesInString:newStr options:0 range:NSMakeRange(0,[newStr length])];
if (noOfMatches==0)
{
return NO;
}
NSUInteger newLength = [textField.text length] + [string length] - range.length;
if(range.length + range.location > textField.text.length)
{
return NO;
}
if ([newStr containsString:#"."])
{
return newLength <= 6;
}
return newLength <= 3;
// return YES;
}
As . is consider as one character. so total would be 6 characters. You can adjust the values in conditions.
This is how you can achieve it using Swift and Regular Expressions:
Set the text field's delegate. This can be done either in code or in IB.
To validate text as it is typed by the user you can add the code to your delegate that is similar to the following:
// Number of digits that are allowed before decimal point
let kMaximumIntegerDigits = 3
// Number of digits that are allowed after decimal point
let kMaximumFractionDigits = 2
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
// The replacement string is empty when the user have removed some characters.
if string.isEmpty == true { return true }
// Get the current string the text field holds.
let currentText = textField.text ?? ""
// Check the limits.
if (string.characters.count + currentText.characters.count) > 6 { return false }
// Get the string we are expecting to obtain after the replacement.
var resultingText = currentText
resultingText.insertContentsOf(string.characters, at: currentText.startIndex.advancedBy(range.location))
// Check the final string with the help of the regular expression.
let regex = "^(?:(?:[0-9]{1,\(kMaximumIntegerDigits)}[.][0-9]{0,\(kMaximumFractionDigits)})|(?:[0-9]){1,\(kMaximumIntegerDigits)})$"
let regexRange = resultingText.rangeOfString(regex, options: .RegularExpressionSearch)
if regexRange == nil { return false }
return true
}
Finally, you should verify the resulting text when the user is trying to end an editing session. You can do it like this:
func textFieldShouldEndEditing(textField: UITextField) -> Bool {
// Get the current input string.
guard let currentText = textField.text else { return false }
// Create the regular expression for the final check.
let regex = "^(?:(?:[0-9]{1,\(kMaximumIntegerDigits)}[.][0-9]{1,\(kMaximumFractionDigits)})|(?:[0-9]){1,\(kMaximumIntegerDigits)})$"
let regexRange = currentText.rangeOfString(regex, options: .RegularExpressionSearch)
if regexRange == nil {
// Show an alert to the user with the message that explains what the input is expected...
return false
}
// Make additional clean-up and finalize the editing session.
return true
}
Thank you so much all folks for helping. By referring those answers I framed below answer.
EDIT
While textfields having e.g. 462. & user touches backspace results to 462 which ideally should result to 46
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString *strTextField = [textField.text stringByReplacingCharactersInRange:range withString:string];
// restrict textfield from entering ./0 at first place
if (strTextField.length > 0) {
NSString *theCharacterAtIndex0 = [NSString stringWithFormat:#"%c", [strTextField characterAtIndex:0]];
if ([theCharacterAtIndex0 isEqualToString:#"."] || [theCharacterAtIndex0 isEqualToString:#"0"]) {
return NO;
}
}
// NSLog(#"%# , %#", textField.text, strTextField);
// automatically add decimal point after 3 digits entered
if (![textField.text containsString:#"."]) {
if (strTextField.length == MAX_LENGTH_BeforeDecimal && ![strTextField containsString:#"."]) {
strTextField = [strTextField stringByAppendingString:#"."];
textField.text = strTextField;
return NO;
}
}
// when decimal is deleted
if ([textField.text containsString:#"."]) {
if (![strTextField containsString:#"."]) {
int indeOfdecimal = (int)[textField.text rangeOfString:#"."].location;
NSString *strBeforeDecimal = [textField.text substringToIndex:indeOfdecimal];
textField.text = strBeforeDecimal;
}
}
NSArray *separator = [strTextField componentsSeparatedByString:#"."];
// to restrict textfield to single decimal
if([separator count] > 2 ) {
return NO;
}
if([separator count] >= 2) {
// restrict the max digits before & after decimal points
NSString *sepStr0 = [NSString stringWithFormat:#"%#",[separator objectAtIndex:0]];
NSString *sepStr1 = [NSString stringWithFormat:#"%#",[separator objectAtIndex:1]];
if ([sepStr0 length] > 3) {
return NO;
}
if ([sepStr1 length] > 2) {
return NO;
}
}
return YES;
}
Use this regex code:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
// Only allow one decimal point and 2 digits after it
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
NSString *expression = #"^[0-9]{0,3}$*((\\.|,)[0-9]{0,2})?$";
NSError *error = nil;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:expression options:NSRegularExpressionCaseInsensitive error:&error];
NSUInteger numberOfMatches = [regex numberOfMatchesInString:newString options:0 range:NSMakeRange(0, [newString length])];
return numberOfMatches != 0;
return YES;
}
The regex used here is "^[0-9]{0,3}$*((\.|,)[0-9]{0,2})?$".
Here number 3 (first bold) denotes the characters before the decimal point and number 2(second bold) denotes the characters after the decimal point.
You can play with this regex and create rule based on your requirement.
I want to format my number into a currency string. These are the following cases
25.00 => $25
25.43 => $25.43
25.4 => $25.40
0.00 -> $0
Is there a way to do this in NSNumberFormatter?
This is my code right now:
NSNumberFormatter *fmt = [[NSNumberFormatter alloc] init];
[fmt setNumberStyle:NSNumberFormatterCurrencyStyle];
[fmt setCurrencyCode:#"USD"];
However that fails for my first and last examples.
I also tried:
NSNumberFormatter *fmt = [[NSNumberFormatter alloc] init];
[fmt setPositiveFormat:#"$0.##"];
However that fails for my third case. Any suggestions?
Change the number of fraction digits based upon whether or not the number is whole.
- (NSString *)stringFromNumber:(NSNumber *)number
{
BOOL isWholeNumber = (roundf(number.doubleValue) == number.doubleValue);
self.currencyNumberFormatter.maximumFractionDigits = self.currencyNumberFormatter.minimumFractionDigits = isWholeNumber ? 0 : 2;
NSString *str = [self.currencyNumberFormatter stringFromNumber:number];
return str;
}
I don't think there's a way to do this using a plain NSNumberFormatter. You could set the minimum and maximum fraction digits to 0 just for formatting integers in a subclass of NSNumberFormatter:
#interface MyCurrencyFormatter : NSNumberFormatter
#end
#implementation MyCurrencyFormatter
- (id)init {
if ((self = [super init])) {
[self setNumberStyle:NSNumberFormatterCurrencyStyle]];
[self setCurrencyCode:#"USD"];
}
return self;
}
- (NSString *)stringFromNumber:(NSNumber *)aNumber {
NSInteger minimumFractionDigits = [self minimumFractionDigits];
NSInteger maximumFractionDigits = [self maximumFractionDigits];
if ([self isInteger:aNumber]) {
[self setMinimumFractionDigits:0];
[self setMaximumFractionDigits:0];
}
NSString *formattedNumber = [super stringFromNumber:aNumber];
[self setMinimumFractionDigits:minimumFractionDigits];
[self setMaximumFractionDigits:maximumFractionDigits];
return formattedNumber;
}
- (BOOL)isInteger:(NSNumber *)aNumber {
NSDecimal decimalValue = aNumber.decimalValue;
NSDecimalRound(&decimalValue, &decimalValue, 0, NSRoundDown);
NSDecimalNumber *roundedValue = [[NSDecimalNumber alloc] initWithDecimal:decimalValue]
return [aNumber isEqualToNumber:roundedValue];
}
#end
This should handle international number formats as well.
Credit to this post for determining if a number is an integer.
I am using the following solution in Swift. It is based on jowie's answer except I do not want to change maximumFractionDigits if my number is not whole. In some countries more than 2 digits are used for prices.
if(price==price.decimalNumberByRoundingAccordingToBehavior(nil))
{
numberFormatter.maximumFractionDigits=0
numberFormatter.minimumFractionDigits=0
}
let priceStr = numberFormatter.stringFromNumber(price)!
A "swifty" way to achieve the desired result, but remain flexible is to set a range by setting the minimum and maximum fraction digits to show:
let price: NSDecimalNumber // 299.0
let priceLocale: Locale // .current
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.locale = priceLocale
formatter.maximumFractionDigits = 2
formatter.minimumFractionDigits = 0
let result = formatter.string(from: price) ?? "" // 299 $
I have a UITextField on my aplication that receives only numeric input from the user. This numeric input represents currency and have the default value of 0.00.
I would like to create something like a mask to format the UITextField as the user enter the numbers. For example:
9 becomes $0,09
99 becomes $0,99
999 becomes $999,99
The code below works great, but as I'm using integer and float values the app will eventually display wrong values afeter a certain point. For example:
999999999 becomes 100000000
That happens because flot and integer aren't precise enough and NSDEcimalNumber should be used. The point is that I can't figure out how to replace my integers and float values to NSDecimalNumber ones.
Does anyone could give me a hand to solve this? I spend some time searching the web for a solution but didn't find that suits my needs and tons of people with the same problem.
Heres the code:
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if (textField.tag == 1){
NSString *cleanCentString = [[textField.text componentsSeparatedByCharactersInSet: [[NSCharacterSet decimalDigitCharacterSet] invertedSet]] componentsJoinedByString:#""];
NSInteger centValue= cleanCentString.integerValue;
if (string.length > 0)
{
centValue = centValue * 10 + string.integerValue;
}
else
{
centValue = centValue / 10;
}
NSNumber *formatedValue;
formatedValue = [[NSNumber alloc] initWithFloat:(float)centValue / 100.0f];
NSNumberFormatter *_currencyFormatter = [[NSNumberFormatter alloc] init];
[_currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
textField.text = [_currencyFormatter stringFromNumber:formatedValue];
return NO;
}
if (textField.tag == 2){
// Nothing for now
}
return YES;
}
Implement UITextFieldDelegate and add next methods:
Swift:
let currencySign = "$"
// Adds $ before the text, e.g. "1" -> "$1" and allows "." and ","
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
{
var value = textField.text
var newString = (textField.text as NSString).stringByReplacingCharactersInRange(range, withString: string)
var components = newString.componentsSeparatedByCharactersInSet(NSCharacterSet(charactersInString: "1234567890,.").invertedSet)
var decimalString = "".join(components) as NSString
var length = decimalString.length
if length > 0 {
value = "\(currencySign)\(decimalString)"
}
else {
value = ""
}
textField.text = value
}
// Formats final value using current locale, e.g. "130,50" -> "$130", "120.70" -> "$120.70", "5" -> "$5.00"
func textFieldDidEndEditing(textField: UITextField) {
var value = textField.text
var components = value.componentsSeparatedByCharactersInSet(NSCharacterSet(charactersInString: "1234567890,.").invertedSet)
var decimalString = "".join(components) as NSString
let number = NSDecimalNumber(string: decimalString, locale:NSLocale.currentLocale())
var formatter = NSNumberFormatter()
formatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle
formatter.locale = NSLocale.currentLocale()
if let formatedValue = formatter.stringFromNumber(number) {
textField.text = formatedValue
}
else {
textField.text = ""
}
}
You can convert integer or double/float value to string by following:
NSString *str = [#(myInt) stringValue];
NSString *str1 = [[NSNumber numberWithFloat:myFloat] stringValue];
After that you can convert string to NSDecimalNumber by many ways. Like:
NSDecimalNumber *number = [NSDecimalNumber decimalNumberWithString:#"100.1"];
NSLog(#"%#", number);
NSDecimalNumber *num = [NSDecimalNumber decimalNumberWithString:#"100.1" locale:NSLocale.currentLocale];
NSLog(#"%#",num);
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
[formatter setLocale:[NSLocale currentLocale]];
NSLog(#"%#", [formatter stringFromNumber:number]);
NSNumberFormatter will help you with the right formatting. Please read apples page for NSDecimalNumber and NSNumberFormatter.
NSNumberFormatter contains a section named"Configuring the Format of Currency". I didn't try it, but it seems something that can help you.
Let me know if this helps.. :)
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!