NSPredicate case-insensitive matching on to-many relationship

62,570

Solution 1

If I understand you correctly, you want your predicate to be true whenever any keywords name matches the search string. For this you need to test with the ANY keyword like this:

[NSPredicate predicateWithFormat:@"ANY keywords.name CONTAINS[c] %@", ...];

This will search the keywords and return true if any of those keywords name contains your search string.

Solution 2

I believe the answer is:

[NSPredicate predicateWithFormat:@"keywords.name CONTAINS[cd] %@", self.searchString];

String comparisons are by default case and diacritic sensitive. You can modify an operator using the key characters c and d within square braces to specify case and diacritic insensitivity respectively, for example firstName BEGINSWITH[cd] $FIRST_NAME.

Predicate Format String Syntax

Solution 3

If you is trying to catch only the equals names but with insensitive case, I think it is the best solution

[NSPredicate predicateWithFormat:@"ANY keywords.name LIKE[c] %@", ...];

You helped me a lot. Thanks guys!!!

In my case I did:

[NSPredicate predicateWithFormat:@"ANY name LIKE[c] %@", @"teste"];

Solution 4

If you must match the keyword but the search must be case-insensitive then you should use NSPredicate(format: "keywords.name =[c] %@", self.searchString)

LIKE does not work on string literals.

Solution 5

If you want both case insensitive and wildcard, use this:

NSPredicate *predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:@"(name like[c] '*%@*')",@"search"]];
Share:
62,570
jksemple
Author by

jksemple

I am an independent developer, writing software for Mac OS X as Fat Cat Software. My current products are iPhoto Library Manager, PowerTunes, FlickrExport, and PlistEdit Pro.

Updated on July 05, 2022

Comments

  • jksemple
    jksemple almost 2 years

    I am implementing a search field where the user can type in a string to filter the items displayed in a view. Each object being displayed has a keywords to-many relationship, and I would like to be able to filter the objects based on their keywords. Each keyword object has a name property, so I've set up an NSPredicate to do the filtering that looks like this:

    NSPredicate* predicate = [NSPredicate predicateWithFormat:@"keywords.name CONTAINS %@", self.searchString];
    

    This works, but the problem is that the search is case-sensitive, so if the keyword has a capital letter but the user types in all lowercase, no matches are found. I've tried the following modification:

    NSPredicate* predicate = [NSPredicate predicateWithFormat:@"keywords.name CONTAINS[c] %@", self.searchString];
    

    But that doesn't make any difference in the case sensitivity of the matching. Is there a way to do this case-insensitive matching using just a plain predicate? Or will I need to implement some sort of custom accessor on the keyword class, e.g. write a lowercaseName method and match against a lowercased version of the search string instead?

    Addendum: After further exploration, the workaround of adding a custom accessor works OK for manual use of NSPredicate, but does not work at all when using NSFetchRequest with Core Data, which only works when querying attributes defined in the Core Data model.

  • jksemple
    jksemple over 14 years
    That's essentially the same as my second attempt posted in the original question, only the addition of the diacritic flag is different. The problem is that this doesn't work when the left hand side of the expression is not a simple string.
  • jksemple
    jksemple over 14 years
    I knew there had to be a way I was missing. Works like a charm. Thanks!
  • Nico
    Nico about 14 years
    LIKE is the glob (?*) matching operator. This will only work correctly if the string you pass for %@ is a glob pattern, because the predicate will interpret it as one; if the string is not a glob pattern, passing it where a glob is expected will cause problems. Use == if you want strict equality.
  • wal
    wal about 14 years
    OH MAN!!!!!!!!!! This works too.. == [c]. I haven't tried this! What's glob patthern, I googled it but ... Is it regular expression?
  • Nico
    Nico about 14 years
    No. Globs are the kind of patterns you use in the shell to match multiple filenames at once.
  • Zeb
    Zeb over 8 years
    For me, the [d] option gave me this error: Terminating app due to uncaught exception 'Invalid predicate option', reason: 'NSDiacriticInsensitivePredicateOption not supported for string type'
  • Zeb
    Zeb over 8 years
    Little tip: for who is using NSPredicate with Realm, LIKE is not supported.
  • Zeb
    Zeb over 8 years
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(name like[c] '*%@*')",@"search"]; is enough.