Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check if an NSString contains a valid number but localized

How to check if a string contains a valid number considering localized number formats.

This question is not primary about converting a number. I can do that with NSNumberFormatter. And if I can't then I don't even need to do it and can leave the string as string. But I need to check whether it contains a valid numer.

BTW, we are in the middle of a textField:shouldChangeCharactersInRange: ... delegate method. Here I want to prevent keying in illegal characters by returning NO.

This is the code that I have:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {

    // Only test for numbers if it is a certain text field. 
    if (textField == self.numValueTextField) {
        NSString *resultingString = [textField.text stringByReplacingCharactersInRange: range withString: string];

        // The user deleting all input is perfectly acceptable.
        if ([resultingString length] == 0) {
            return true;
        }

        double holder;

        NSScanner *scan = [NSScanner scannerWithString: resultingString];

        BOOL isNumeric = [scan scanDouble: &holder] && [scan isAtEnd];

        if (isNumeric) {

            [self.detailItem setValue:number forKey:kValueDouble];
        }

        return isNumeric;
    }
    return YES;  // default for any other text field - if any.
}

That works fine but it implies English notations. Meaning the floating point must be a pont. But it could be a comma or whatever in certain parts of the world.

I do know how to check for certain characters. So I could check for 0-9, comma and point. But is there a 'proper' way of doing that?

If it is of importance: I am in an iOS environment.

like image 784
Hermann Klecker Avatar asked Mar 11 '13 22:03

Hermann Klecker


1 Answers

A number formatter will use the current locale's information by default, so it should be able to do this checking for you. Just try to format the string. If the result is nil, then it's not valid.

static NSNumberFormatter * formatter = [NSNumberFormatter new];
//... build string
NSNumber * num = [formatter numberFromString:resultingString];
BOOL isNumeric = (num != nil);

For example:

NSNumberFormatter * formatter = [NSNumberFormatter new];

// US uses period as decimal separator
[formatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];

NSLog(@"%@", [formatter numberFromString:@"3.1415"]);   // Valid NSNumber
NSLog(@"%@", [formatter numberFromString:@"3.14.15"]);  // nil
NSLog(@"%@", [formatter numberFromString:@"31415"]);    // Valid
NSLog(@"%@", [formatter numberFromString:@"3,1415"]);   // nil

// Italy uses a comma as decimal separator
[formatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"it"]];
NSLog(@"%@", [formatter numberFromString:@"3.1415"]);    // nil
NSLog(@"%@", [formatter numberFromString:@"3.14.15"]);   // nil
NSLog(@"%@", [formatter numberFromString:@"31415"]);     // Valid
NSLog(@"%@", [formatter numberFromString:@"3,1415"]);    // Valid

Or you might prefer to use getObjectValue:forString:range:error:, which will simply return YES or NO to indicate success at parsing, and also give you an error object if you're interested in further details.

like image 52
jscs Avatar answered Oct 05 '22 18:10

jscs