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.)
Related
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];
}
}
i have text message and I want to check whether it is containing text "http" or URL exists in that.
How will I check it?
NSString *string = #"xxx http://someaddress.com";
NSString *substring = #"http:";
Case sensitive example:
NSRange textRange = [string rangeOfString:substring];
if(textRange.location != NSNotFound){
//Does contain the substring
}else{
//Does not contain the substring
}
Case insensitive example:
NSRange textRange = [[string lowercaseString] rangeOfString:[substring lowercaseString]];
if(textRange.location != NSNotFound){
//Does contain the substring
}else{
//Does not contain the substring
}
#Cyprian offers a good option.
You could also consider using a NSRegularExpression which would give you far more flexibility assuming that's what you need, e.g. if you wanted to match http:// and https://.
Url usually has http or https in it
You can use your custom method containsString to check for those strings.
- (BOOL)containsString:(NSString *)string {
return [self containsString:string caseSensitive:NO];
}
- (BOOL)containsString:(NSString*)string caseSensitive:(BOOL)caseSensitive {
BOOL contains = NO;
if (![NSString isNilOrEmpty:self] && ![NSString isNilOrEmpty:string]) {
NSRange range;
if (!caseSensitive) {
range = [self rangeOfString:string options:NSCaseInsensitiveSearch];
} else {
range = [self rangeOfString:string];
}
contains = (range.location != NSNotFound);
}
return contains;
}
Example :
[yourString containsString:#"http"]
[yourString containsString:#"https"]
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 (#"")."
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];}
I'm playing with the TableSearch sample application from Apple.
In their application, they have an array with Apple products. There is one row with "iPod touch". When searching for "touch", no results are displayed.
Can someone help me making all the words in each row searchable? So that results are found when searching for "iPod" but also for the keyword "touch".
Cheers.
Below is the relevant code in the filterContentForSearchText:scope: method in MainViewController.m:
NSComparisonResult result = [product.name compare:searchText options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch) range:NSMakeRange(0, [searchText length])];
if (result == NSOrderedSame)
{
[self.filteredListContent addObject:product];
}
This compares the first n characters (specified by the range parameter), ignoring case and diacritics, of each string with the first n characters of the current search string, where n is the length of the current search string.
Try changing the code to the following:
NSRange result = [product.name rangeOfString:searchText options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch)];
if (result.location != NSNotFound)
{
[self.filteredListContent addObject:product];
}
This searches each string for the current search string.