问题
I am trying to construct a query of a Core Data store which retrieves an entity's attribute values when they occur in longer string;
i.e, instead of seeking instances where attribute value contains a (shorter) string :
request.predicate = [NSPredicate predicateWithFormat:@"carBrand contains[c] 'merced'"]
I want to find instances (of the entity) whose attribute values are found 'contained in' an arbitrary (longer) string :
NSString* textString = @"Elaine used to drive Audis, but now owns a Mercedes";
request.predicate = [NSPredicate predicateWithFormat:@"%@ contains[c] carBrand", textString ];
(ie. retrieve array holding objects with carBrand = @"Audi" and carBrand = @"Mercedes")
In my attempts, NSPredicate doesn't seem to like expressions with the attribute name on the right hand side and throws an error...
[__NSCFConstantString countByEnumeratingWithState:objects:count:]: unrecognized selector sent to instance 0x
...is there a way of constructing such a query with the attribute name on the left hand side - a 'contained_by' query, as it were?
PS. Searching SO, I've only found solutions by splitting the text into component words which, in my scenario, would be less than ideal! Is this the only type of approach that's viable?
回答1:
Build a regex string with your array and use MATCHES
in your predicate.
[NSPredicate predicateWithFormat:@"%@ MATCHES '*(Audi|Mercedes)*'", testString];
To filter cars based on their brand:
NSArray *brands = [@"Audi", @"Mercedes"];
[NSPrediate predicateWithFormat:@"carBrand IN %@", brands];
回答2:
Decided to try implementing a componentsSeparatedByString
approach to build a NSCompoundPredicate
//find alphabetic words omitting standard plurals
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"(?:[^a-z]*)([a-z]+?)(?:s)?\\W+" options:NSRegularExpressionCaseInsensitive error:nil];
//separate with pipe| and split into array
NSString *split = [regex stringByReplacingMatchesInString:textString options:0 range:NSMakeRange(0, speciesString.length) withTemplate:@"$1|"];
NSArray *words = [split componentsSeparatedByString:@"|"];
//build predicate List
NSMutableArray *predicateList = [NSMutableArray array];
for (NSString *word in words) {
if ([word length] > 2) {
NSPredicate *pred = [NSPredicate predicateWithFormat:@"brandName beginswith[c] %@", word];
[predicateList addObject:pred];
}
}
//CarBrand* object;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = [NSEntityDescription entityForName:@"CarBrand" inManagedObjectContext:self.managedObjectContext];
request.predicate = [NSCompoundPredicate orPredicateWithSubpredicates:predicateList];
NSError *error =nil;
NSArray *results = [self.managedObjectContext executeFetchRequest:request error:&error];
This retrieves the instances found in the text; eg1:
@"Elaine used to drive Audis, but now owns a Mercedes";
gives array of objects whose .brandname = "Audi", "Mercedes", respectively .
eg2: @"Among the cars stolen were a Ford Mondeo, a Fiat 500C and an Alfa-Romeo Spyder"
yields .brandname = "Ford", "Fiat",and "Alfa Romeo"(NB no '-') respectively.
I'm not yet accepting my own answer as it seems too much of a workaround and won't easily extend to (for example) extracting brand-name AND, say, model.
Hopefully, someone will have a better solution!
来源:https://stackoverflow.com/questions/26778320/writing-an-nspredicate-for-contained-by-text-query