Issue with NSRegularExpression / RegEx to validate Postal Code - ios

I have the following two methods, where I am calling an NSRegularExpression (first time using this) with two separate patterns, one to check against Canadian and the other American Postal/Zip codes.
-(BOOL)isValidPostalCode:(NSString*)code
{
BOOL isValid = NO;
NSString *cdnCheck = #"^[ABCEGHJKLMNPRSTVXY]\d[A-Z][- ]*\d[A-Z]\d$";
NSString *usCheck = #"^\d{5}(-\d{4})?$";
if ([self validateString:code withPattern:cdnCheck] || [self validateString:code withPattern:usCheck]) {
isValid = YES;
}
return isValid;
}
- (BOOL)validateString:(NSString *)string withPattern:(NSString *)pattern
{
NSError *error = nil;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionCaseInsensitive error:&error];
if (error)
{
NSLog(#"Couldn't create regex with given string and options");
}
NSRange textRange = NSMakeRange(0, string.length);
NSRange matchRange = [regex rangeOfFirstMatchInString:string options:NSMatchingReportProgress range:textRange];
NSTextCheckingResult *resultString = [regex firstMatchInString:string options:0 range:textRange];
BOOL didValidate = NO;
if (matchRange.location != NSNotFound) {
didValidate = YES;
}
return didValidate;
}
In the second method, matchRange's length is always 0 (which I think is an indicator of no match?), and resultString is always nil... And I can't figure out why.
What am I doing wrong?
-- DISCLAIMERS --
a) I am passing a string - with no whitespaces - such as 'V6E1H8' or '90210', so those are valid candidates
b) Yes, I know those are redundant checks in the second method, I am just debugging with various other options from the Class Reference and thought to leave it in there...
c) FYI, I got the expressions from this answer (and a few more) and they check out on http://regexpal.com/, so I am assuming that the patterns themselves are valid, and it's an issue with my logic (I am admittedly a bit fuzzy on how NSRange works and how the NSRegEx (excuse the shorthand) evaluates a valid result...

Related

How to detect if the string is Base64 encoded or not? [Objective-c]

I am struggling here to make this work, i have to detect the string which i am receiving in the response is base64 encoded or not and handle it accordingly.
I have tried two ways so far:
1.
if ([input length] % 4 == 0 && input.length >= 3) {
static NSCharacterSet *invertedBase64CharacterSet = nil;
if (invertedBase64CharacterSet == nil) {
invertedBase64CharacterSet = [[NSCharacterSet characterSetWithCharactersInString:#"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="]invertedSet];
}
return [input rangeOfCharacterFromSet:invertedBase64CharacterSet options:NSLiteralSearch].location == NSNotFound;
}
return NO;
2.
NSString *expression = regexString;
NSError *error = nil;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:expression options:NSRegularExpressionCaseInsensitive error:&error];
NSUInteger numberOfMatches = [regex numberOfMatchesInString:self options:0 range:NSMakeRange(0, [self length])];
if (numberOfMatches > 0) {
return YES;
} else {
return NO;
}
Everything is working fine except when the string is 4 characters in length like 'Adam' both above snippets considers this as a base64 string which is not correct.
If anyone know better way to detect the Base64 string please let me know and it should work for string of 4 characters in length also.
Thanks in advance.

iOS Regular Expression to check whether a NSString starts with g

I am new to Regular Expressions and its usage in iOS .I have a scenario where I have to check whether a NSString starts with 'G' this is my function which returns the bool condition . I am passing the data like this
[self compareStringWithRegex:#"Gmail" withRegexPattern:#".*g"];
-(BOOL) compareStringWithRegex:(NSString *) string withRegexPattern:(NSString *)expression
{
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:expression options:NSRegularExpressionCaseInsensitive error:&error];
NSTextCheckingResult *match = [regex firstMatchInString:string options:0 range:NSMakeRange(0, [string length])];
if (match){
return YES;
}else{
return NO;
}
}
The problem I am facing is, this function returns true if I give wrong condition . Please help me in this and let me know if my question is not clear .
If you want to use Regular Expressions to check string start with "g" then
replace ".*g" with "^g" it will give you asspected result
[self compareStringWithRegex:#"Gmail" withRegexPattern:#"^g"];
If you really want to use regex the #"(g)+(\\w+)" should work. I tested it on Regex Tester

Regex to Match Characters in Words in iOS

Hi i am Trying to Match Characters in Words Same as Email Search while Sending Emails. Where popover is shown. By Typing text, Text is Highlighted in Popover.
Anna Haro
anna-haro#mac.com
Hank M. Zakroff
hank-zakroff#mac.com
what is Tried is,
\bHa[\w-]*
Expecting Match as,
Anna Haro
anna-haro#mac.com
Hank M. Zakroff
hank-zakroff#mac.com
Here are the way that you can highlight search string from whole string.
Step 1 : Add following method. that is created NSRegularExpression object for you.
- (NSRegularExpression *)regularExpressionWithString:(NSString *)string options:(NSDictionary *)options
{
// Create a regular expression
BOOL isCaseSensitive = [[options objectForKey:kRWSearchCaseSensitiveKey] boolValue];
BOOL isWholeWords = [[options objectForKey:kRWSearchWholeWordsKey] boolValue];
NSError *error = NULL;
NSRegularExpressionOptions regexOptions = isCaseSensitive ? 0 : NSRegularExpressionCaseInsensitive;
NSString *placeholder = isWholeWords ? #"\\b%#\\b" : #"%#";
NSString *pattern = [NSString stringWithFormat:placeholder, string];
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:regexOptions error:&error];
if (error)
{
NSLog(#"Couldn't create regex with given string and options");
}
return regex;
}
Step 2 : Here are the code that highlight the find string from whole string.
// 4: Call the convenient method to create a regex for us with the options we have
NSRegularExpression *regex = [self regularExpressionWithString:searchString options:options];
// 5: Find matches
NSArray *matches = [regex matchesInString:visibleText options:NSMatchingProgress range:visibleTextRange];
// 6: Iterate through the matches and highlight them
for (NSTextCheckingResult *match in matches)
{
NSRange matchRange = match.range;
[visibleAttributedText addAttribute:NSBackgroundColorAttributeName value:[UIColor yellowColor] range:matchRange];
}
Refer for more help
Edit :
Replace
NSString *placeholder = #"\\b%#";
With
NSString *placeholder = isWholeWords ? #"\\b%#\\b" : #"%#";
Hope this help you.

How to work with the results from NSRegularExpression when using the regex pattern as a string delimiter

I'm using a simple pattern with NSRegularExpression to delimit content within a string:
(\s)+(and|or)(\s)+
So, when I use matchesInString it's not the matches that I'm interested in, but the other stuff.
Below is the code that I'm using. Iterating over the matches and then using indexes and lengths to pull out the content.
Question: I'm just wondering if I'm missing something in the api to get the other bits? Or, is the approach below generally ok?
- (NSArray*)separateText:(NSString*)text
{
NSString* regExPattern = #"(\\s)+(and|or)(\\s)+";
NSError* error = NULL;
NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:regExPattern
options:NSRegularExpressionCaseInsensitive
error:&error];
NSArray* matches = [regex matchesInString:text options:0 range:NSMakeRange(0, text.length)];
if (matches.count == 0) {
return #[text];
}
NSInteger itemStartIndex = 0;
NSMutableArray* result = [NSMutableArray new];
for (NSTextCheckingResult* match in matches) {
NSRange matchRange = [match range];
if (!matchRange.location == 0) {
NSInteger matchStartIndex = matchRange.location;
NSInteger length = matchStartIndex - itemStartIndex;
NSString* item = [text substringWithRange:NSMakeRange(itemStartIndex, length)];
if (item.length != 0) {
[result addObject:item];
}
}
itemStartIndex = NSMaxRange(matchRange);
}
if (itemStartIndex != text.length) {
NSInteger length = text.length - itemStartIndex;
NSString* item = [text substringWithRange:NSMakeRange(itemStartIndex, length)];
[result addObject:item];
}
return result;
}
You can capture the string before the and|or with parentheses, and add it to your array with rangeAtIndex.
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"(.+?)(\\s+(and|or)\\W+|\\s*$)" options:NSRegularExpressionCaseInsensitive error:&error];
NSMutableArray *phrases = [NSMutableArray array];
[regex enumerateMatchesInString:string options:0 range:NSMakeRange(0, [string length]) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
NSRange range = [result rangeAtIndex:1];
[phrases addObject:[string substringWithRange:range]];
}];
A couple of minor points about my regex:
I added the |\\s*$ construct to capture the last string after the final and|or. If you don't want that, you can eliminate that.
I replaced the second \\s+ (whitespace) with a \\W+ (non-word characters), in case you encountered something like and|or followed by a comma or something else. You could alternatively look explicitly for ,?\\s+ if the comma was the only non-word character you cared about. It just depends upon the specific business problem you're solving.
You might want to replace the first \\s+ with \\W+, too.
If your string contains newline characters, you might want to use the NSRegularExpressionDotMatchesLineSeparators option when you instantiate the NSRegularExpression.
You could replace all matches of the regex with a template string (e.g. ", " or "," etc) and then separate the string components based on that new delimiter.
NSString *stringToBeMatched = #"Your string to be matched";
NSString *regExPattern = #"(\\s)+(and|or)(\\s)+";
NSError *error = nil;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regExPattern
options:NSRegularExpressionCaseInsensitive
error:&error];
if (error) {
// handle error
}
NSString *replacementString = [regex stringByReplacingMatchesInString:stringToBeMatched
options:0
range:NSMakeRange(0, stringToBeMatched.length)
withTemplate:#","];
NSArray *otherItemsInString = [replacementString componentsSeparatedByString:#","];

Input mask Textfield with Regex

I try to create an input mask for an UITextField for enter aircraft callsign. The mask should be "F-" and 4 letters. I try it with regular expression but it doesn't work fine. I show you my code. It is impossible to enter any character with it.
if (textField==_tImmat) {
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
NSString *expression = #"^(F-)([A-Z]{4})$";
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;
}
Any ideas to create regex which works fine for a string value like this :"F-XXXX" where X is an uppercase letter?
Thanks for your help...
I'm guessing that code is in your shouldChangeCharactersInRange method?
If so, because you are imposing of this specific format, no other string can ever be entered, i.e. unless the value of newString is F-<4 LETTERS>, the method will return NO.
So you can either move your validation to textFieldShouldReturn method:
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
NSString *expression = #"^(F-)([A-Z]{4})$";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:expression options:NSRegularExpressionCaseInsensitive error:nil];
NSUInteger numberOfMatches = [regex numberOfMatchesInString:textField.text options:0 range:NSMakeRange(0, [textField.text length])];
if (numberOfMatches == 0)
{
NSLog(#"wrong format!");
}
else
{
NSLog(#"correct format!");
}
return NO;
}
(by the way, for options you are using NSRegularExpressionCaseInsensitive which means it will allow user to put in both uppercase and lowercase characters and validate them as correct)
If you'd like to validate as the user types and restrict input of illegal characters, I'd change your code to something like this:
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
switch (newString.length)
{
case 0:
//allow user empty string
return YES;
case 1:
//check that first character is F
return [newString isEqualToString:#"F"];
case 2:
//check that the second character is -
return [newString isEqualToString:#"F-"];
case 3 ... 6:
//this will check the last four characters based on your regex
{
NSString *expression = #"^(F-)([A-Z]{0,4})$"; //notice the added range
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;
}
else
{
return YES;
}
}
default:
//in all other cases validation will fail
return NO;
}
Your validation only accepts the value F-XXXX. Starting with a black text field if the user enters the F, your validation fails because it's not F-XXXX.
You need to let the user enter each character and only fail the validation if the entered text can't possibly ever match the pattern.
There's no reason to use a regular expression for this. Just scan newString. Make sure it starts with an F. If the length is 2 or more, check that the 2nd character is a ```. Then simply make sure the length is less than 6 and the last few characters are the letters A-Z.

Resources