Question

I'm working on a small iphone project and i would need to check if the userName entered only contains alphanumerical characters? (A-Z, a-z, 0-9. How would i go about checking it?

Was it helpful?

Solution

If you don't want to bring in a regex library for this one task...

NSString *str = @"aA09";
NSCharacterSet *alphaSet = [NSCharacterSet alphanumericCharacterSet];
BOOL valid = [[str stringByTrimmingCharactersInSet:alphaSet] isEqualToString:@""]; 

OTHER TIPS

This will work:

@implementation NSString (alphaOnly)

- (BOOL) isAlphaNumeric
{
    NSCharacterSet *unwantedCharacters = 
       [[NSCharacterSet alphanumericCharacterSet] invertedSet];

    return ([self rangeOfCharacterFromSet:unwantedCharacters].location == NSNotFound);
}

@end

You can use this regular expression library for ObjectiveC. Use the following regex to match:

^[a-zA-Z0-9]*$

The NSCharacterSet based answers do not give the results you might expect for Japanese etc text, often claiming that they do contain alphanumeric characters - the test being performed boils down to 'are there only letters or numbers', and Japanese (etc) characters count as 'Letters'.

If you're trying to check Latin characters vs a foreign language (eg. Japanese), then the answer from " How to determine if an NSString is latin based? " may help:

BOOL isLatin = [myString canBeConvertedToEncoding:NSISOLatin1StringEncoding];

NSASCIIStringEncoding could also be used instead of NSISOLatin1StringEncoding to further restrict the valid characters. You could also test using NSCharacterSet afterwards, to exclude special characters like !, #, etc.

I've run some rather extensive performance testing and there are several considerations to take into account when choosing how to validate your alphanumeric strings. First, of course, is that you may not even care about performance. If your app rarely validates strings, or perhaps even only does it once, whatever method that gives you the behavior you want is fine. Beyond that, here are my performance results.

For custom character sets (say alphanumeric characters, without Unicode characters or marks), this is fastest for an initial run:

NSCharacterSet *alphanumericSet = [NSCharacterSet characterSetWithCharactersInString:@"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"];
NSString *result = [self stringByTrimmingCharactersInSet:alphanumericSet];

return [result isEqualToString:@""];

If you're okay using a precomputed character set like [NSCharacterSet alphanumericCharacterSet] then this was fastest:

NSCharacterSet *alphanumericSet = [NSCharacterSet alphanumericCharacterSet];
alphanumericSet = alphanumericSet.invertedSet;
NSRange range = [self rangeOfCharacterFromSet:alphanumericSet];

return (range.location == NSNotFound);

Caching the character set in a static variable using dispatch_once can help quite a bit if you run these validations repeatedly. In that case, if you're certain you can absorb the initial compilation time, using a regex actually turns out to be the fastest for custom character sets:

static NSRegularExpression *alphanumericRegex;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    alphanumericRegex = [NSRegularExpression regularExpressionWithPattern:@"^[a-zA-Z0-9]*$" options:NSRegularExpressionCaseInsensitive error:nil];
});
NSUInteger numberOfMatches = [alphanumericRegex numberOfMatchesInString:self options:0 range:NSMakeRange(0, self.length)];

return (numberOfMatches == 1);

If you don't wish to use the regex, the custom set version of the cached rangeOfCharacterFromSet edges out the cached stringByTrimmingCharactersInCharacterSet: method:

static NSCharacterSet *alphanumericSet;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    alphanumericSet = [NSCharacterSet characterSetWithCharactersInString:@"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"];
    alphanumericSet = alphanumericSet.invertedSet;
});

NSRange range = [self rangeOfCharacterFromSet:alphanumericSet];

return (range.location == NSNotFound);

For precomputed sets, the cached rangeOfCharacterFromSet: method was again the fastest:

static NSCharacterSet *alphanumericSet;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    alphanumericSet = [NSCharacterSet alphanumericCharacterSet];
    alphanumericSet = alphanumericSet.invertedSet;
});

NSRange range = [self rangeOfCharacterFromSet:alphanumericSet];

return (range.location == NSNotFound);

And for everyone's information, the isSupersetOfSet: method was the slowest, whether cached or not. Looks like isSupersetOfSet: is pretty slow.

NSCharacterSet *stringSet = [NSCharacterSet characterSetWithCharactersInString:self];
NSCharacterSet *alphanumericSet = [NSCharacterSet alphanumericCharacterSet];

return [alphanumericSet isSupersetOfSet:stringSet];

I didn't do any testing of the underlying CFCharacterSet functions.

- (BOOL)isAlphaNumeric
{
     NSCharacterSet *s = [NSCharacterSet characterSetWithCharactersInString:@"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'. "];
     s = [s invertedSet];
     NSRange r = [self rangeOfCharacterFromSet:s];
     if (r.location == NSNotFound) {
         return NO;
     } else {
       return YES;
    }
}

Has the flexibility to add/ subtract new characters like whitespaces

P.S This method can be copy/paste in NSString category

I really like the RegexKit Lite Framework. It uses the ICU regex library, which is already included with OSX and is unicode-safe.

NSString *str = @"testString";
[str isMatchedByRegex:@"^[a-zA-Z0-9]*$"]; // strict ASCII-match
[str isMatchedByRegex:@"^[\p{L}\p{N}]*$"]; // unicode letters and numbers match

You can use NSString regular expression capabilities, introduced in iOS 3.2:

- (BOOL)isAlphanumeric:(NSString *)string {
    return [string rangeOfString:@"^[a-zA-Z0-9]+$" options:NSRegularExpressionSearch].location != NSNotFound;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top