Validating strings against given regex pattern? - ios

I wrote simple method for checking if given array has at least one string, that matches provided pattern... but something is missing and not sure how to limit positive results only to full words, not just first substring that fits pattern.
+ (BOOL)hasWordsWithPattern:(NSString *)pattern inWords:(NSArray *)words{
NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:pattern
options:NSRegularExpressionCaseInsensitive
error:nil];
for (NSString *s in words) {
if ([expression matchesInString:s
options:0
range:NSMakeRange(0, s.length)]) {
NSLog(#"there is a match!");
return YES;
}
}
NSLog(#"sorry, no match found!");
return NO;
}

Silly me, there is easier way to do that :) based on https://stackoverflow.com/a/5777016/1015049
+ (BOOL)hasWordsWithPattern:(NSString *)pattern inWords:(NSArray *)words{
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", pattern];
for (NSString *s in words) {
if ([predicate evaluateWithObject:s]) {
NSLog(#"there is a match!");
return YES;
}
}
NSLog(#"sorry, no match found!");
return NO;
}

Related

Issue with NSRegularExpression / RegEx to validate Postal Code

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...

Regexp matching group not working on objective-c

I'm trying to get from this string: 5556007503140005
Two strings. "555600750314" and "0005"
I'm Using the regexp ^([a-z0-9]*)([0-9]{4})$that works fine on the regexp tools, but when i use this on my code I only get 1 match.
this is the code
-(NSDictionary *)parse_barcode:(NSString *)barcode {
NSString *regexp = #"^([a-z0-9]*)([0-9]{4})$";
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF MATCHES %#",regexp];
if ([predicate evaluateWithObject:barcode]) {
NSError *error;
NSRegularExpression *regular_exp = [NSRegularExpression regularExpressionWithPattern:regexp options:0 error:&error];
NSArray *matches = [regular_exp matchesInString:barcode options:0 range:NSMakeRange(0, [barcode length])];
for (NSTextCheckingResult *match in matches) {
NSLog(#"match %# :%#",[barcode substringWithRange:[match range]], match);
}
}
return nil;
}
But the match is always the entire string (Barcode)
You get the right match, you are just not printing them correctly. You need to use numberOfRanges to get the individual groups (i.e. sections enclosed in parentheses), and then call rangeAtIndex: for each group, like this:
for (NSTextCheckingResult *match in matches) {
for (int i = 0 ; i != match.numberOfRanges ; i++) {
NSLog(#"match %d - %# :%#", i, [barcode substringWithRange:[match rangeAtIndex:i]], match);
}
}

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:#","];

check if one big string contains another string using NSPredicate or regular expression

NSString *string = #"A long term stackoverflow.html";
NSString *expression = #"stack(.*).html";
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", expression];
BOOL match = [predicate evaluateWithObject:string]
if(match){
NSLog(#"found");
} else {
NSLog(#"not found");
}
how can i search if expression is present in string or not. above code is working for one word. but not if i put some more words in string to be searched
If you would like to check a string with a regex value then you should use NSRegularExpression not NSPredicate.
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"stack(.*).html" options:0 error:nil];
Then you can use the functions to find matches...
NSString *string = #"stackoverflow.html";
NSUInteger matchCount = [regex numberOfMatchesInString:string options:0 range:NSMakeRange(0, string.length)];
NSLog(#"Number of matches = %d", matchCount);
Note: I'm terrible at creating regex patterns so I have just used your pattern and example. I have no idea if the pattern will actually find a match in this string but if there is a match it will work.
NSPredicate only matches complete strings, so you should change your pattern to cover the whole string:
NSString *expression = #".*stack(.*).html.*";
However, your original pattern will also match something like "stack my files high as html", so you may want to read up on your regex patterns.
Improve your question , but see below answer for your question
NSString *string = #"This is the main stringsss which needs to be searched for some text the texts can be any big. let us see";
if ([string rangeOfString:#"."].location == NSNotFound) {
NSLog(#"string does not contains");
} else {
NSLog(#"string contains !");
}

How to check the validity of a GUID (or UUID) using NSRegularExpression or any other effective way in Objective-C

The method should return TRUE if the NSString is something like #"{A5B8A206-E14D-429B-BEB0-2DD0575F3BC0}" and FALSE for a NSString like #"bla bla bla"
I am using something like:
- (BOOL)isValidGUID {
NSError *error;
NSRange range = [[NSRegularExpression regularExpressionWithPattern:#"(?:(\\()|(\\{))?\\b[A-F0-9]{8}(?:-[A-F0-9]{4}){3}-[A-Z0-9]{12}\\b(?(1)\\))(?(2)\\})" options:NSRegularExpressionCaseInsensitive error:&error] rangeOfFirstMatchInString:self.GUID options:0 range:NSMakeRange(0, [self.GUID length])];
if (self.GUID && range.location != NSNotFound && [self.GUID length] == 38) {
return TRUE;
} else {
return NO;
}
}
but it is not working as I have expected.
Important: GUID which I am using is enclosed by curly braces like this: {A5B8A206-E14D-429B-BEB0-2DD0575F3BC0}
This function will do the job..
-(BOOL)isValidUUID : (NSString *)UUIDString
{
return (bool)[[NSUUID alloc] initWithUUIDString:U‌​UIDString];
}
Thanks #Erzékiel
This regex matches for me
\A\{[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{12}\}\Z
In short:
\A and \Z is the beginning and end of the string
\{ and \} is escaped curly bracets
[A-F0-9]{8} is exactly 8 characters of either 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F
As an NSRegularExpression it would look like this
NSError *error = NULL;
NSRegularExpression *regex =
[NSRegularExpression regularExpressionWithPattern:#"\\A\\{[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{12}\\}\\Z"
options:NSRegularExpressionAnchorsMatchLines
error:&error];
// use the regex to match the string ...
You can use the following method to check this:
- (BOOL)isUUID:(NSString *)inputStr
{
BOOL isUUID = FALSE;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" options:NSRegularExpressionCaseInsensitive error:nil];
NSInteger matches = [regex numberOfMatchesInString:inputStr options:0 range:NSMakeRange(0, [inputStr length])];
if(matches == 1)
{
isUUID = TRUE;
}
return isUUID;
}
Consider the shortened UUID format. Use code below:
-(BOOL)isValidUUID:(NSString*)uuidString{
NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:uuidString];
if (uuid ) {
return YES;
}
NSError *error;
NSRegularExpression *reg = [NSRegularExpression regularExpressionWithPattern:#"[^0-9|^a-f]" options:NSRegularExpressionCaseInsensitive error:&error];
NSArray *matches = [reg matchesInString:uuidString options:NSMatchingReportCompletion range:NSMakeRange(0, uuidString.length)];
if (matches.count == 0 && (uuidString.length == 4 || uuidString.length ==8) ) {
return YES;
}else{
return NO;
}
}

Resources