Search is only matching words at the beginning - iphone

In one of the code examples from Apple, they give an example of searching:
for (Person *person in personsOfInterest)
{
NSComparisonResult nameResult = [person.name compare:searchText
options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch)
range:NSMakeRange(0, [searchText length])];
if (nameResult == NSOrderedSame)
{
[self.filteredListContent addObject:person];
}
}
Unfortunately, this search will only match the text at the start. If you search for "John", it will match "John Smith" and "Johnny Rotten" but not "Peach John" or "The John".
Is there any way to change it so it finds the search text anywhere in the name? Thanks.

Try using rangeOfString:options: instead:
for (Person *person in personsOfInterest) {
NSRange r = [person.name rangeOfString:searchText options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch)];
if (r.location != NSNotFound)
{
[self.filteredListContent addObject:person];
}
}
Another way you could accomplish this is by using an NSPredicate:
NSPredicate *namePredicate = [NSPredicate predicateWithFormat:#"name CONTAINS[cd] %#", searchText];
//the c and d options are for case and diacritic insensitivity
//now you have to do some dancing, because it looks like self.filteredListContent is an NSMutableArray:
self.filteredListContent = [[[personsOfInterest filteredArrayUsingPredicate:namePredicate] mutableCopy] autorelease];
//OR YOU CAN DO THIS:
[self.filteredListContent addObjectsFromArray:[personsOfInterest filteredArrayUsingPredicate:namePredicate]];

-[NSString rangeOfString:options:] and friends are what you want. It returns:
"An NSRange structure giving the location and length in the receiver of the first occurrence of aString, modulo the options in mask. Returns {NSNotFound, 0} if aString is not found or is empty (#"")."

Related

Objective regex evaluateWithObject is not working

When I tried matching the string with the regex '^(34|37)' it does not work even after giving the correct one. Can anyone please point out or guide me to what I am doing wrong?
This is my code:
NSPredicate *myTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", #"^(34|37)"];
if([myTest evaluateWithObject: #"378282246310005"]){
NSLog(#"match");
}
Your regex will not match the given string. That is ^(34|37) does not match 378282246310005. It matches the first two characters, but after that it fails because the string contains more characters, while your regex terminates.
You need to alter your regex to match the rest of the characters, even if you don't want to capture them. Try changing your regext to ^(34|37).*.
Make seprate method for matching regex as bool type. Then it will work.
like this
- (IBAction)tapValidatePhone:(id)sender
{
if(![self validateMobileNo:self.txtPhoneNo.text] )
{
NSLog(#"Mobile No. is not valid");
}
}
-(BOOL) validateMobileNo:(NSString *) paramMobleNo
{
NSString *phoneNoRegex = #"^(34|37)";
NSPredicate *phoneNoTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#",phoneNoRegex];
return [phoneNoTest evaluateWithObject:#"3435"];
}
it is not going in else condition.
Why not just use hasPrefix:
if([#"378282246310005" hasPrefix:#"34"] || [#"378282246310005" hasPrefix:#"37"])
{
NSLog(#"found it");
}
EDIT:
Using NSPredicate:
NSPredicate *myTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", #"^3(4|7)\\d+$"];
if([myTest evaluateWithObject: #"378282246310005"])
{
NSLog(#"match");
}
else
{
NSLog(#"notmatch");
}
Using NSRegularExpression:
NSError *error = nil;
NSString *testStr = #"348282246310005";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"^3(4|7)" options:NSRegularExpressionCaseInsensitive error:&error];
NSInteger matches = [regex numberOfMatchesInString:testStr options:NSMatchingReportCompletion range:NSMakeRange(0, [testStr length])];
if(matches > 0 )//[myTest evaluateWithObject: #"378282246310005"])
{
NSLog(#"match");
}
else
{
NSLog(#"notmatch");
}
BTW: (34|37) does not look 34 or 37 instead it seems 347 or 337 to me, since engine will pick 4|3 either 4 or 3.

how to write NSRegularExpression to xx:xx:xx?

i am trying to check if NSString is in specific format. dd:dd:dd. I was thinking of NSRegularExpression. Something like
/^(\d)\d:\d\d:\d\d)$/ ?
Have you tried something like:
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"^\d{2}:\d{2}:\d{2}$"
options:0
error:&error];
NSUInteger numberOfMatches = [regex numberOfMatchesInString:string
options:0
range:NSMakeRange(0, [string length])];
(I haven't tested it, because I cannot right now, but it should be working)
I suggest to use RegexKitLite
With this and assuming that in dd:dd:dd 'd' actually stands for a digit from 0-9 it should be fairly easy to implement what you need given the additional comment from Grijesh.
Here's an example copied from the RegexKitLite page:
// finds phone number in format nnn-nnn-nnnn
NSString *regEx = #"{3}-[0-9]{3}-[0-9]{4}";
NSString *match = [textView.text stringByMatching:regEx];
if ([match isEqual:#""] == NO) {
NSLog(#"Phone number is %#", match);
} else {
NSLog(#"Not found.");
}
UPDATE:
NSString *idRegex = #"[0-9][0-9]:[0-9][0-9]:[0-9][0-9]";
NSPredicate *idTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", idRegex];
for (NSString * str in newArrAfterPars) {
if ([idTest evaluateWithObject:str]) {
}
}

How to Search 2nd word in a string of array using UISearchBar?

I have to search a word in an array using UISearchBar. for example i have "Chicken Salad" string in an array at index 2. now if want to search it using last word "Salad" then what should i do?
for the time i am using this code and it is working good but if you search from first word.
(appDelegate.isAirlineSelection == YES) {
for (int i = 0; i < [menuArray count]; i++) {
if ([[[[menuArray objectAtIndex:i] itemName] uppercaseString] hasPrefix:search]||[[[[menuArray objectAtIndex:i] itemName] uppercaseString] hasSuffix:search]) {
[tableMenuArray addObject:[menuArray objectAtIndex:i]];
NSLog(#"Found");
}
}
Kindly help me
try this way, It'll search even between the words:
for(NSString *name in menuArray)
{
if ([name rangeOfString:search options:NSLiteralSearch|NSCaseInsensitiveSearch].location != NSNotFound)
[tableMenuArray addObject:name];
NSLog(#"Found");
}
First you should break your array name in two parts and create two arrays, then you can easily use search bar for second array and can find exact result ,what do you want.
for (NSString *name in lastnames)
{
NSComparisonResult result = [name compare:searchText options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch) range:NSMakeRange(0, [searchText length])];
if (result == NSOrderedSame)
{
[searchedNames addObject:name];
}
}

NSComparisonResult search part of a string?

I am using NSComparisonResult with my SearchController:
for (Annotation *ano in listContent) {
NSComparisonResult result = [ano.title compare:searchText options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch) range:NSMakeRange(0, [searchText length])];
if (result == NSOrderedSame) {
[self.filteredListContent addObject:ano];
}
}
If I search for a string it will only find the result if it starts with that string.
Record is "My Art Gallery"
Search for "My Art Gallery" <---
Found
Search for "My " <--- Found
Search for "Art" <--- Not Found
Search for "Gallery" <--- Not found
How can I change my code so that I can find parts of the string as I showed above?
I ended up using NSRange which allowed me to basically search for a substring:
for (Annotation *ano in listContent) {
NSRange range = [ano.title rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (range.location != NSNotFound) {
[self.filteredListContent addObject:ano];
}
}
There is a straight forward way to do a substring check:
NSComparisonResult result1 = [dummyString compare:searchText options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch) range:[dummyString rangeOfString:searchText options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch)]];
if (result1 == NSOrderedSame)
{
[self.filteredListContent addObject:dummyString]; // this can vary drastically
}
NOTE: I am using this with a UISearchDisplayController and this worked perfectly for me.
Hope this helps you in future.
Thanks to this post (UPDATE: This link doesn't work anymore.)

iPhone 'Whole Word' Search

I am currently using the following algorithm to search on my iPhone app:
NSRange range = [entry.englishEntry rangeOfString:searchText options:NSCaseInsensitiveSearch];
if(range.location != NSNotFound)
{
[self.filteredListContent addObject:entry];
}
The problem is that when I search for a word like 'crap' I also get results for words like 'scrap' which is irrelevant. I am unfamiliar with NSRange so what is the search algorithm for searching the whole word?
I just solved this problem by adding a simple category on NSString to do a word boundary search. Here's the code:
#interface NSString (FullWordSearch)
// Search for a complete word. Does not match substrings of words. Requires fullWord be present
// and no surrounding alphanumeric characters.
- (BOOL)containsFullWord:(NSString *)fullWord;
#end
#implementation NSString (FullWordSearch)
- (BOOL)containsFullWord:(NSString *)fullWord {
NSRange result = [self rangeOfString:fullWord];
if (result.length > 0) {
if (result.location > 0 && [[NSCharacterSet alphanumericCharacterSet] characterIsMember:[self characterAtIndex:result.location - 1]]) {
// Preceding character is alphanumeric
return NO;
}
if (result.location + result.length < [self length] && [[NSCharacterSet alphanumericCharacterSet] characterIsMember:[self characterAtIndex:result.location + result.length]]) {
// Trailing character is alphanumeric
return NO;
}
return YES;
}
return NO;
}
#end
Yes you can search within words. You need to split the string into components first. Then loop through each one and compare them.
Something like that:
NSArray *words = [entry.english componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
for (NSString *word in words)
{
NSComparisonResult result = [word compare:searchText options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch) range:NSMakeRange(0, [searchText length])];
if (result == NSOrderedSame)
{
[self.filteredListContent addObject:entry];
break;
}
}
Instead of finding the range of a string, just do a case-insensitive compare and check if the result is NSOrderedSame
if([entry.english caseInsensitiveCompare:searchText] == NSOrderedSame){
[self.filteredListContent addObject:entry];
}
This will compare the text with the whole word and not just look for the range.
Now i make it as more generic, by using this code you can search any string between target string
NSString * strName =[entry.english lowercaseString];
if ([strName rangeOfString:[searchText lowercaseString]].location != NSNotFound) {
[self.filteredListContent addObject:entry];}