textField validation on real time in objective-C - ios

I have a TextField in xCode and someone ask me to admit just certain types of characters giving me this text string:
^([A-ZÑÑÁÉÍÓÚÀÈÌÒÙÄËÏÖÜ ])*$
or this one:
^([0-9])*$
I Know a method using UITextFieldDelegate named textField shouldChangeCharactersInRange and this is the way I implement this method:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString *allowedCharacters = #"abcdefghijklmnñopqrstuvwxyzABCDEFGHIJKLMÑNOPQRSTUVWXYZ0123456789.#-_ ";
NSCharacterSet *characterSet = [NSCharacterSet characterSetWithCharactersInString:allowedCharacters];
if ([string stringByTrimmingCharactersInSet:characterSet].length == 0)textField.text = [textField.text stringByReplacingCharactersInRange:range withString:string];
return NO;
return YES;
}
if you see, on my programming my variable allowedCharacters stores all my valid characters but is in a different format (I have to write all the allowed characters),
I want to program something similar but with my partner's text format ^([0-9])*$ (text using ranges) how do I do that
Thanks in advance

you can use this:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
// Valida el patron que se introduce en el campo de texto
if (![self validateString:string withPattern:#"^([A-Z0-9.#-_ ])*$"]) return NO;
return YES;
}
in the withPattern parameter insert your regex expression, and then here it is the method which does all the magic:
- (BOOL)validateString:(NSString *)string withPattern:(NSString *)pattern
{
NSError *error = nil;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionCaseInsensitive error:&error];
NSAssert(regex, #"Unable to create regular expression");
NSRange textRange = NSMakeRange(0, string.length);
NSRange matchRange = [regex rangeOfFirstMatchInString:string options:NSMatchingReportProgress range:textRange];
BOOL didValidate = NO;
// Did we find a matching range
if (matchRange.location != NSNotFound) didValidate = YES;
return didValidate;
}
test it and tell us how did it go

Related

Regex in iOS to limit a text field to only letters and single apostrophies

After a text field is returned I want to check if the text provided is valid. Valid means only letters or a single apostrophe, for names.
I'm pretty new to regular expressions. Is there a simple regular expression I can use for this check, or can someone point me towards some reading material where I can learn to compose a regular expression that will fit my needs?
You can do it like this, but you need to show an error in case the input is invalid.
- (BOOL)textFieldShouldEndEditing:(UITextField *)aTextField
{
NSString *const regularExpression = #"^[a-zA-Z']+$";
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regularExpression
options:kNilOptions
error:&error];
if (error) {
// Handle error
}
NSUInteger numberOfMatches = [regex numberOfMatchesInString:aString
options:0
range:NSMakeRange(0, [aString length])];
return numberOfMatches > 0;
}
The regx should be
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
you can use
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
if (textField == emailid) {
NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:#"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'"] invertedSet];
NSString *filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:#""];
;
return [string isEqualToString:filtered];
}
}
You can use the function that checks whether the input should be inserted or not and restrict the characters there. Since your restriction is fairly simple there is no need of regular expressions and you can use characters sets.
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
NSMutableCharacterSet *allowedCharacters = [NSMutableCharacterSet alphanumericCharacterSet];
[allowedCharacters addCharactersInString:#"'"];
if([string rangeOfCharacterFromSet:allowedCharacters.invertedSet].location == NSNotFound){
return YES;
}
return NO;
}

How to restrict UITextField to a defined set of characters and limit the length?

I am working on a login and resister view controller. I am limiting usernames to 12 characters and passwords to 16 using :
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if(textField==self.userField){
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
return !([newString length] > 12);
}
else if(textField==self.passwordField){
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
return !([newString length] > 16);
}
return YES;
}
this works well but I also want to limit it to a set of characters to stop unwanted symbols and also Chinese characters. I want to define this set:
#define ACCEPTABLE_CHARACTERS #"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
Not sure how to add it to the method above though and get both working. If I was to check for the character set only and not length the code would be:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:ACCEPTABLE_CHARACTERS] invertedSet];
NSString *filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:#""];
return [string isEqualToString:filtered];
}
Not sure how to combine them though. Can someone help me please? Thanks!
You can do it like (I divided it to function for more readability and easy to scale the conditions)
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
return ([self checkLengthOfString:newString inField:textField] && [self checkCharacter:newString]);
}
// Check Length
- (BOOL)checkLengthOfString:(NSString *)text inField:(UITextField *)textField
{
if(textField == self.userField)
{
return !([text length] > 12);
}
else if(textField == self.passwordField)
{
return !([text length] > 16);
}
}
// Check character
- (BOOL)checkCharacter:(NSString *)text
{
BOOL status = YES;
NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:ACCEPTABLE_CHARACTERS] invertedSet];
NSRange r = [text rangeOfCharacterFromSet:s];
if (r.location != NSNotFound)
{
status = NO;
}
return status;
}
Why don't you just use a regEx to match that chars?
I know this has already been answered, but I had a similar scenario and I found none of the answers on StackOverflow handled the Backspace character.
I needed to limit input into a UITextField to a specific number of AlphaNumeric characters, but be able to enter spaces.
Also, using [textField length] > kMAXNUMCHARS caused a problem: you couldn't backspace once you hit the max number of chars.
So here's my complete solution. It also disallows leading spaces. Trailing spaces are trimmed elsewhere when the value is saved (in my case to a PLIST file)
In my Constants.h file I defined:
#define ALLOWED_CHARECTERS #" ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
extern const int kMAXUSERNAMELENGTH;
then in Constants.m:
const int kMAXUSERNAMELENGTH = 9;
I define my class as UITextFieldDelegate with the line
[self._txtUsername.textField setDelegate:self];
Don't forget to declare the UITextFieldDelegate protocol in your class definiion
#interface MyClass : CCNode <UITextFieldDelegate>
And finally,
//UITextFiledDelegate Protocol method
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
//disallow leading spaces. must allow trailing spaces- never know if we'll add another char
//we trim trailing spaces when we save the TextField value, in our case to Plist file
if (range.location == 0 && [string isEqualToString:#" "])
return NO;
//we use defined ALLOWED_CHARECTERS so we can add chars later, easily.
//we could use [NSCharacterSet alphanumericCharacterSet] if we don't need to allow spaces
NSCharacterSet *allowedInput = [NSCharacterSet characterSetWithCharactersInString:ALLOWED_CHARECTERS];
NSArray* arChar = [string componentsSeparatedByCharactersInSet:allowedInput]; //arChar.count = 1 if 'allowedInput' not in 'string'
//disallow input if its not a backspace (replacementString paramater string equal #"" if a backspace) AND
//(disallow input >= kMAXUSERNAMELENGTH chars, OR disallow if not in allowed allowedChar set
if ( ![string isEqual:#""] && ( [textField.text length] >= kMAXUSERNAMELENGTH || !([arChar count] > 1)) )
return NO;
return YES;
}
I hope this helps someone.

Editing textfield after "endEdit" with ShouldChangeCharactersInRange implemented

I have the following code implemented to restrict my user to enter in more than 2 decimal points and places after they have entered the first one. Users can still edit the textfield as long as they don't "leave" or "endEdit" the textfield. However, once they leave the textfield and go back, the textfield is not editable. How can I solve this problem?
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if (textField == self.SalesAmounttext)
{
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
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;
}
return YES;
}
All I had to do was add in the clearsOnInsertion code and everything works! Thanks to #Wain
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if (textField == self.SalesAmounttext)
{
textField.clearsOnInsertion=YES ; // HERE
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
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;
}
return YES;
}
Your logic places very tight restrictions on the user so any arbitrary edit will not be permitted. From a user standpoint that will probably be quite confusing so good options would be:
Set clearsOnInsertion when the text field is created so that each edit is a fresh start
Alert the user about invalid edits
Allow each edit and then format at the end of editing and alert the user to any issue then

Allow only 2 whitespace in text

I have a UITextField and I want to allow user enter in this field maximum 2 whitespace. How I can do it?
I think I need to check something here:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {}
But what to check? I have searched the web, but nothing found.
You want to use a regular expression for this. The expression \s\s+ means two or more spaces, carriage returns or tabs.
NSString *text = textField.text;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:
#"(\s\s+)" options:0 error:nil];
[regex replaceMatchesInString:str options:0 range:NSMakeRange(0, [str length]) withTemplate:#" "];
textField.text = text;
This will return how many spaces there are in the string
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
int numberOfSpaces = [[textField.text componentsSeparatedByString:#" "] count];
if (numberOfSpace > 2) {
//notify user that he/she has too many spaces
}
}
Also you seem new to iOS. Don't forget to set your view controller as a UITextField delegate.

Appending the decimal automatically while typing in the UITextField

I am having a UITextField in which I had limited the number of characters to 4 before decimal and 3 to after decimal. I have done this through
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string{
if (textField == txt_weightKg)
{
NSString *newString = [textField.text stringByReplacingCharactersInRange:range
withString:string];
NSString *expression = #"^([0-9]{1,4}+)?(\\.([0-9]{1,3})?)?$";
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;
}
return YES;
}
This is only for keeping the validation but now I want i actually want is that As soon as I start typing in the UITextfield a decimal is automatically appended with the number. The second condition is that as I reaches the 4 digits the next digit should be after the decimal. For example:-
if I entered 1 it should look like 1. , for 2 digits 11. this has to continue up to 4 digits and then as soon as I eneter the fifth digit it should place that 5th digit after the decimal as 1111.1 which will continue to 3 places after decimal.
If somebody can help me then It will be greatly appreciated! feel free to ask in case of confusion.
I think i achieved what you required by following code:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
//create character set containing numbers only
NSCharacterSet * set = [[NSCharacterSet characterSetWithCharactersInString:#"0123456789"] invertedSet];
if (textField.text.length >= 8 && range.length == 0)
{
return NO;
}
else
{
if ([string rangeOfCharacterFromSet:set].location != NSNotFound) {
return NO;
}
else
{
int length = [textField.text length];
//append a decimal after 4 digits
if([textField.text length] ==4 && string.length != 0)
{
textField.text = [NSString stringWithFormat:#"%#.",textField.text];
}
return YES;
}
}
}
Please confirm your response to this.

Resources