Find and detect "#" and "#" with NSRegularExpression - ios

I am trying to find "#" and "#" sign in my text with NSRegularExpression like that;
NSString *testString = #"This text contains # and # signs";
NSRange stringRange = NSMakeRange(0, [testString length]);
NSRegularExpression *regexTest = [[NSRegularExpression alloc] initWithPattern:#"\\b(#|#)\\b"];
NSRange nameRange = [regexTest rangeOfFirstMatchInString:testString options:0 range:stringRange];
When i NSLog nameRange.location, it's always return 0. What is the correct form to find that signs with NSRegularExpression?

This is how I did it using NSPredicate. This tells you the current #mention word that's being edited/typed. Hope this helps.
- (void)textViewDidChange:(UITextView *)textView
{
_words = [self.textView.text componentsSeparatedByString:#" "];
NSPredicate* predicate = [NSPredicate predicateWithFormat:#"SELF BEGINSWITH[cd] '#'"];
NSArray* names = [_words filteredArrayUsingPredicate:predicate];
if (_oldArray)
{
NSMutableSet* set1 = [NSMutableSet setWithArray:names];
NSMutableSet* set2 = [NSMutableSet setWithArray:_oldArray];
[set1 minusSet:set2];
if (set1.count > 0)
NSLog(#"Results %#", set1);
}
_oldArray = [[NSArray alloc] initWithArray:names];
}

Related

Check if there is a word after a word (NSSTRING)

I have a fun little tricky problem. So I need to create an if statement that can detect if there is a word after a word in an array
so my code is
NSArray *words = [texfield.text componentsSeparatedByString:#" "];
int index = [words indexOfObject:#"string"];
I am not sure if I have to do something like
NSString*needle=words[index+1];
if (needle isEqualto #"") {
//There is a word after #"string";
}
What should I do?
How can I determine is there is a word after #"string"?
I appreciate all the help!! :)
Yeah, you have to:
NSArray *words = [texfield.text componentsSeparatedByString:#" "];
NSInteger index = [words indexOfObject:#"string"];
NSInteger afterIndex = index+1;
if(afterIndex<words.count) {
NSString *needle = words[index+1];
if (needle isEqualToString #"") {
//do something
}
}
NSString *yourString = #"string stackoverflow word after string regex";
NSRange yourStringRange = NSMakeRange(0, [yourString length]);
NSString *pattern = #"string\\s*([^\\s]*)";
NSError *error = nil;
NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern: pattern options:0 error:&error];
NSArray* matches = [regex matchesInString:yourString options:0 range: yourStringRange];
for (NSTextCheckingResult* match in matches) {
NSRange rangeForMatch = [match rangeAtIndex:1];
NSLog(#"word after STRING: %#", [yourString substringWithRange:rangeForMatch]);
}
Output:
word after STRING: stackoverflow
word after STRING: regex
Method componentsSeparatedByString: will give all components separated by input NSString.
Your eg. NSArray *words = [texfield.text componentsSeparatedByString:#" "];
will have all string separated by " ". So just check if any
NSInteger afterIndex = index+1;
if(afterIndex<words.count) if Yes, you have NSStringavailable.

How to use regular expression match "in iOS

For example , the following is the source I want match:
<div class="cont">
I use
<div\s+class\=\"cont\">
But it doesn't work , if I modify the expression like
<div\s+class\=.*?cont.*?>
Now , it can give me the result I want .
So I think , the problem should be in " this character.
Following is the code I use in iOS , it can works for some other regular expression:
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:reg options:NSRegularExpressionCaseInsensitive error:nil];
NSArray *matches = [regex matchesInString:resultStr options:0 range:NSMakeRange(0, [resultStr length])];
for (NSTextCheckingResult *match in matches) {
NSRange matchRange = [match range];
NSString *tagString = [resultStr substringWithRange:matchRange];
[resultArr addObject:tagString];
}
You are trying to match HTML with regular expressions. It is definitely very troublesome, since HTML you receive can be all uppercase, single quotes may be used instead of double or be missing, etc.
That said, if you really need a regex solution, I'd recommend to account for any number of attributes before class=cont and allow any attribute value delimiters:
NSString *pattern = #"<div\\b[^<]*class=[\"']?cont\\b[^<]*>";
Here, I am using \b to match a word boundary, [^<]* checks for any other attributes before class, ["']? allows either a single or double quotation mark or nothing, then \b makes sure cont is followed by a non-word character, and [^<]* checks for any other attributes before final >.
Also, \" is escaped once as it is a C string delimiter and \\b is escaped twice to make sure we pass \b to the regex engine.
Sample code at CodingGround:
#import <Foundation/Foundation.h>
#import <Foundation/NSTextCheckingResult.h>
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSError *error = nil;
NSString *pattern = #"<div\\b[^<]*class=[\"']?cont\\b[^<]*>";
NSString *string = #"<div class=\"cont\">";
NSRange range = NSMakeRange(0, string.length);
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:&error];
NSArray *matches = [regex matchesInString:string options:0 range:range];
for (NSTextCheckingResult *match in matches) {
NSRange matchRange = [match range];
NSString *m = [string substringWithRange:matchRange];
NSLog(#"Matched string: %#", m);
}
[pool drain];
return 0;
}
Here goes the code:
NSString *stricterFilterString = #"[A-Z0-9a-z\\._%+-]+#([A-Za-z0-9-]+\\.)+[A-Za-z]{2,4}";
NSString *laxString = #".+#([A-Za-z0-9]+\\.)+[A-Za-z]{2}[A-Za-z]*";
NSString *emailRegex = stricterFilter ? stricterFilterString : laxString;
NSPredicate *emailTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", emailRegex];

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

Find dynamically word in NSString

NSString * stringExample1=#"www.mysite.com/word-4-word-1-1-word-word-2-word-817061.html";
NSString * stringExample2=#"www.mysite.com/word-4-5-1-1-word-1-5-word-11706555.html";
I try to find - and . Inside of NSString.
NSRange range = [string rangeOfString:#"-"];
NSUInteger start = range.location;
NSUInteger end = start + range.length;
NSRange rangeDot= [string rangeOfString:#"."];
NSUInteger startt = rangeDot.location;
NSUInteger endt = startt + rangeDot.length;
But it's can't be successful. It's showing first place. How can I get 817061 and 11706555 inside of Nstring?
Thank you .
This will work for you,
NSArray *strArry=[stringExample1 componentsSeparatedByString:#"-"];
NSString *result =[strArry lastObject];
NSString *resultstring= [result stringByReplacingOccurrencesOfString:#".html" withString:#""];
Are you trying to find if it contains at least one of - or . ?
You can use -rangeOfCharacterFromSet:
NSCharacterSet *CharacterSet = [NSCharacterSet characterSetWithCharactersInString:#"-."];
NSRange range = [YourString rangeOfCharacterFromSet:CharacterSet];
if (range.location == NSNotFound)
{
// no - or . in the string
}
else
{
// - or . are present
}
Try this simple Regular Expression.
NSString * stringExample1=#"www.mysite.com/word-4-word-1-1-word-word-2-word-84354354353.html";
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression
regularExpressionWithPattern:#"(\\-\\d*\\.)"
options:0
error:&error];
NSRange range = [regex rangeOfFirstMatchInString:stringExample1
options:0
range:NSMakeRange(0, [stringExample1 length])];
range = NSMakeRange(range.location+1, range.length-2);
NSString *result = [stringExample1 substringWithRange:range];
NSLog(#"%#",result);
I think the best way to find the match is by using regulars expressions with NSRegularExpression.
NSString * stringEx=#"www.mysite.com/word-4-word-1-1-word-word-2-word-817061.html";
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"-(\\d*).html$"
options:NSRegularExpressionCaseInsensitive
error:&error];
NSArray *matches = [regex matchesInString:stringEx options:NSMatchingReportCompletion range:NSMakeRange(0, [stringEx length])];
if ([matches count] > 0)
{
NSString* resultString = [stringEx substringWithRange:[matches[0] rangeAtIndex:1]];
NSLog(#"Matched: %#", resultString);
}
Make sure you use an extra \ escape character in the regex NSString whenever needed.
UPDATE
I did a test using the two different approaches (regex vs string splitting) with the code below:
NSDate *timeBefore = [NSDate date];
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"-(\\d*).html$"
options:NSRegularExpressionCaseInsensitive
error:&error];
for (int i = 0; i < 100000; i++)
{
NSArray *matches = [regex matchesInString:stringEx options:NSMatchingReportCompletion range:NSMakeRange(0, [stringEx length])];
if ([matches count] > 0)
{
NSString* resultString = [stringEx substringWithRange:[matches[0] rangeAtIndex:1]];
}
}
NSTimeInterval timeSpent = [timeBefore timeIntervalSinceNow];
NSLog(#"Time: %.5f", timeSpent*-1);
on the simulator the differences are not significant, but running on an iPhone 4 I got the following results:
2013-11-25 10:24:19.795 NotifApp[406:60b] Time: 11.45771 // string splitting
2013-11-25 10:25:10.451 NotifApp[412:60b] Time: 7.55713 // regex
so I guess the best approach depends on case to case.

How to use regular expressions to find words that begin with a three character prefix

My goal is to count the number of words (in a string) that begin with a specified prefix of more than one letter. A case is words that begin with "non". So in this example...
NSString * theFullTestString = #"nonsense non-issue anonymous controlWord";
...I want to get hits on "nonsense" and "non-issue", but not on "anonymous" or "controlWord". The total count of my hits should be 2.
So here's my test code which seems close, but none of the regular expression forms I've tried works correctly. This code catches "nonsense" (correct) and "anonymous" (wrong) but not "non-issue" (wrong). Its count is 2, but for the wrong reason.
NSUInteger countOfNons = 0;
NSString * theFullTestString = #"nonsense non-issue anonymous controlWord";
NSError *error = nil;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"non(\\w+)" options:0 error:&error];
NSArray *matches = [regex matchesInString:theFullTestString options:0 range:NSMakeRange(0, theFullTestString.length)];
for (NSTextCheckingResult *match in matches) {
NSRange wordRange = [match rangeAtIndex:1];
NSString* word = [theFullTestString substringWithRange:wordRange];
++countOfNons;
NSLog(#"Found word:%# countOfNons:%d", word, countOfNons);
}
I'm stumped.
The regex \bnon[\w-]* should do the trick
\bnon[\w-]*
^ (\b) Start of word
^ (non) Begins with non
^ ([\w-]) A alphanumeric char, or hyphen
^ (*) The character after 'non' zero or more times
So, in your case:
NSUInteger countOfNons = 0;
NSString * theFullTestString = #"nonsense non-issue anonymous controlWord";
NSError *error = nil;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"(\\bnon[\\w-]*)" options:0 error:&error];
NSArray *matches = [regex matchesInString:theFullTestString options:0 range:NSMakeRange(0, theFullTestString.length)];
for (NSTextCheckingResult *match in matches) {
NSRange wordRange = [match rangeAtIndex:1];
NSString* word = [theFullTestString substringWithRange:wordRange];
++countOfNons;
NSLog(#"Found word:%# countOfNons:%d", word, countOfNons);
}
I think regular expressions are a bit of an overkill here.
NSString *words = #"nonsense non-issue anonymous controlWord";
NSArray *wordsArr = [words componentsSeparatedByString:#" "];
int count = 0;
for (NSString *word in wordsArr) {
if ([word hasPrefix:#"non"]) {
count++;
NSLog(#"%dth match: %#", count, word);
}
}
NSLog(#"Count: %d", count);
There is more easier way to do this. You can use NSPredicate and use this format BEGINSWITH[c] %#.
Sample code
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"Firstname BEGINSWITH[c] %#", text];
NSArray *results = [People filteredArrayUsingPredicate:resultPredicate];

Resources