Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TextField Validation With Regular Expression

I need help with code that looks at a textfield make sure it starts with either a (+ or -) then has 3 integers after it.

So valid data looks like +234 or -888

So I have started this code but there are 2 problems with it

  1. It correctly validates that only 4 characters are entered. But for some reason you have to take focus off the textfield in order for the Done button on the keyboard to fire and hide the keyboard. If I only put less than 4 characters in the textfield then the Done button works fine. But I dont want the user to enter anything but 4 characters and then press Done and hide the keyboard. Thats the first problem....

  2. I am not familar with regular expressions and how to use them in iphone. So I need to add to this code regular expression for the above requirement.

    -(BOOL)textField:(UITextField*)textFieldshouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
    {
         NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
         return !([newString length] > 4);
    }
    //Done button to hide the keyboard
    -(IBAction)Done:(id)sender
    {
    
    }
    
like image 519
Nick LaMarca Avatar asked Apr 23 '11 17:04

Nick LaMarca


2 Answers

Use UIPickerView instead

I am departing from the question title but IMHO considering what you need, it may be better to use UIPickerView to have a "spinning-wheel" type of entry, like you do in the Clock app when setting alarm. It can start at "+000" and user can tumble some of the four wheels ([+-]. [0-9], [0-9], [0-9]) as needed

like image 152
Nas Banov Avatar answered Oct 10 '22 17:10

Nas Banov


I am not sure how you'd like to handle user input and feedback. First I'll show a simple way to keep the user in the editing mode of the textField if her input is not valid.

First of all two delegate methods:

- (BOOL)textFieldShouldReturn:(UITextField *)aTextField
{
    [aTextField resignFirstResponder];
    return YES;
}

- (BOOL)textFieldShouldEndEditing:(UITextField *)aTextField
{
    return [self validateInputWithString:aTextField.text];
}

The testing method, which just returns YES or NO whether the input is valid or not:

- (BOOL)validateInputWithString:(NSString *)aString
{
    NSString * const regularExpression = @"^([+-]{1})([0-9]{3})$";
    NSError *error = NULL;
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regularExpression
                                                                           options:NSRegularExpressionCaseInsensitive
                                                                             error:&error];
    if (error) {
        NSLog(@"error %@", error);
    }

    NSUInteger numberOfMatches = [regex numberOfMatchesInString:aString
                                                        options:0
                                                          range:NSMakeRange(0, [aString length])];
    return numberOfMatches > 0;
}

That's it. However I'd recommend showing some live status to the user whether his input is ok or not. Add the following notifcation, for example in your viewDidLoad method:

- (void)viewDidLoad
{
    // ...
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(validateInputCallback:) 
                                                 name:@"UITextFieldTextDidChangeNotification" 
                                               object:nil];
}

- (void)validateInputCallback:(id)sender
{
    if ([self validateInputWithString:textField.text]) {
        // For example turn a label green and let it say: "OK"
    } else {
        // For example turn a label red and let it say: "Allowed: + or minus followed by exactly three digits"
    }
}

Finally: If you need to access the capture groups (+ or - and the number) of the regular expression the following code will help:

// ... reg ex creation ...
NSArray *matches = [regex matchesInString:aString
                                  options:0
                                    range:NSMakeRange(0, [aString length])];

for (NSTextCheckingResult *match in matches) {
    for (int i = 0; i < [match numberOfRanges]; i++) {
        NSLog(@"range %d: %d %d", i, [match rangeAtIndex:i].location, [match rangeAtIndex:i].length);
        NSLog(@"substring %d: %@", i, [aString substringWithRange:[match rangeAtIndex:i]]);
    }
}
like image 24
Nick Weaver Avatar answered Oct 10 '22 16:10

Nick Weaver