Writing an NSPredicate for 'CONTAINED_BY' text query

徘徊边缘 提交于 2019-12-11 12:27:29

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!