Spotlight can do exact searches using quotation marks, IE %a"tom waits" will do a case insensitive search for all music by Tom Waits

CQTexperiment
matthewleon 2008-02-14 17:48:32 +00:00
parent d6e7efd2c1
commit 70ae3cec1c
3 changed files with 69 additions and 16 deletions

View File

@ -11,6 +11,8 @@
@interface NSComparisonPredicate (CogPredicate) @interface NSComparisonPredicate (CogPredicate)
+ (NSPredicate *)predicateForMdKey:(NSString *)key withString:(NSString *)aString; + (NSPredicate*)predicateForMdKey:(NSString*)key
withString:(NSString*)aString
exactString:(BOOL)exactString;
@end @end

View File

@ -14,12 +14,17 @@ static const unsigned OPTIONS = (NSCaseInsensitivePredicateOption|
@implementation NSComparisonPredicate (CogPredicate) @implementation NSComparisonPredicate (CogPredicate)
+ (NSPredicate *)predicateForMdKey:(NSString *)key withString:(NSString *)aString + (NSPredicate*)predicateForMdKey:(NSString *)key
withString:(NSString *)aString
exactString:(BOOL)exactString
{ {
NSString * likeString = [NSString stringWithFormat:@"*%@*", aString]; // We don't want an exact string, so wrap it in wildcards
if(!exactString)
aString = [NSString stringWithFormat:@"*%@*", aString];
return [NSComparisonPredicate return [NSComparisonPredicate
predicateWithLeftExpression:[NSExpression expressionForKeyPath:key] predicateWithLeftExpression:[NSExpression expressionForKeyPath:key]
rightExpression:[NSExpression expressionForConstantValue:likeString] rightExpression:[NSExpression expressionForConstantValue:aString]
modifier:NSDirectPredicateModifier modifier:NSDirectPredicateModifier
type:NSLikePredicateOperatorType type:NSLikePredicateOperatorType
options:OPTIONS]; options:OPTIONS];

View File

@ -81,49 +81,95 @@ static NSPredicate * musicOnlyPredicate = nil;
NSMutableArray *subpredicates = [NSMutableArray arrayWithCapacity:10]; NSMutableArray *subpredicates = [NSMutableArray arrayWithCapacity:10];
NSScanner *scanner = [NSScanner scannerWithString:self.searchString]; NSScanner *scanner = [NSScanner scannerWithString:self.searchString];
BOOL exactString;
NSString * scannedString;
NSMutableString * parsingString;
while (![scanner isAtEnd]) while (![scanner isAtEnd])
{ {
NSString *scannedString; exactString = NO;
if ([scanner scanUpToString:@" " intoString:&scannedString]) if ([scanner scanUpToString:@" " intoString:&scannedString])
{ {
if ([scannedString length] < MINIMUM_SEARCH_STRING_LENGTH) if ([scannedString length] < MINIMUM_SEARCH_STRING_LENGTH)
continue; continue;
if ([scannedString characterAtIndex:0] == '%') // We use NSMutableString because this string will get abused a bit
// It potentially could be reading the entire search string
parsingString = [NSMutableString stringWithCapacity: [self.searchString length]];
[parsingString setString: scannedString];
if ([parsingString characterAtIndex:0] == '%')
{ {
if ([scannedString length] < (MINIMUM_SEARCH_STRING_LENGTH + 2)) if ([parsingString length] < (MINIMUM_SEARCH_STRING_LENGTH + 2))
continue; continue;
if ([parsingString characterAtIndex:2] == '\"')
{
exactString = YES;
// If the string does not end in a quotation mark and we're not at the end,
// scan until we find one.
// Allows strings within quotation marks to include spaces
if ([parsingString characterAtIndex:([parsingString length] - 1)] != '\"' &&
![scanner isAtEnd])
{
NSString *restOfString;
[scanner scanUpToString:@"\"" intoString:&restOfString];
[parsingString appendFormat:@" %@", restOfString];
}
else if ([parsingString characterAtIndex:([parsingString length] - 1)] == '\"')
{
// pick off the quotation mark at the end
[parsingString deleteCharactersInRange:
NSMakeRange([parsingString length] - 1, 1)];
}
// eliminate beginning quotation mark
[parsingString deleteCharactersInRange: NSMakeRange(2, 1)];
}
// Search for artist // Search for artist
if([scannedString characterAtIndex:1] == 'a') if([parsingString characterAtIndex:1] == 'a')
{ {
[subpredicates addObject: [subpredicates addObject:
[NSComparisonPredicate predicateForMdKey:@"kMDItemAuthors" [NSComparisonPredicate predicateForMdKey:@"kMDItemAuthors"
withString:[scannedString substringFromIndex:2]]]; withString:[parsingString substringFromIndex:2]
exactString:exactString]];
} }
// Search for album // Search for album
if([scannedString characterAtIndex:1] == 'l') if([parsingString characterAtIndex:1] == 'l')
{ {
[subpredicates addObject: [subpredicates addObject:
[NSComparisonPredicate predicateForMdKey:@"kMDItemAlbum" [NSComparisonPredicate predicateForMdKey:@"kMDItemAlbum"
withString:[scannedString substringFromIndex:2]]]; withString:[parsingString substringFromIndex:2]
exactString:exactString]];
} }
// Search for title // Search for title
if([scannedString characterAtIndex:1] == 't') if([parsingString characterAtIndex:1] == 't')
{ {
[subpredicates addObject: [subpredicates addObject:
[NSComparisonPredicate predicateForMdKey:@"kMDItemTitle" [NSComparisonPredicate predicateForMdKey:@"kMDItemTitle"
withString:[scannedString substringFromIndex:2]]]; withString:[parsingString substringFromIndex:2]
exactString:exactString]];
}
// Search for genre
if([parsingString characterAtIndex:1] == 'g')
{
[subpredicates addObject:
[NSComparisonPredicate predicateForMdKey:@"kMDItemMusicalGenre"
withString:[parsingString substringFromIndex:2]
exactString:exactString]];
} }
} }
else else
{ {
[subpredicates addObject: [subpredicates addObject:
[NSComparisonPredicate predicateForMdKey:@"*" [NSComparisonPredicate predicateForMdKey:@"*"
withString:scannedString]]; withString:parsingString
exactString:exactString]];
} }
} }
} }