NSPredicate для поиска по нескольким словам - PullRequest
10 голосов
/ 14 февраля 2011

В моем приложении для iOS у меня есть очень простой предикат для моего контроллера извлечения.

NSString *format = [NSString stringWithFormat:@"name like[c] '%@'", nameVar];
NSPredicate *predicate = [NSPredicate predicateWithFormat:format];
[fetchController setPredicate:predicate];

Он выполняет базовый поиск имени без учета регистра.Теперь я хотел бы изменить его так, чтобы я мог поместить несколько слов в поле поиска (nameVar имеет значение из поля поиска), разделенных пробелами, и предикат отфильтровывает результаты, соответствующие всем этим ключевым словам.

Поэтому, если у меня есть два имени: «Джон Смит» и «Мэри Смит», и я ищу: «Смит М», я хотел бы получить только один результат, но такой поиск: «Sm th ih» должен возвращать оба значения.

У кого-нибудь есть идеи, как это реализовать?

1 Ответ

32 голосов
/ 14 февраля 2011

редактировать вернуться на обычный компьютер ...

Итак, есть пара вещей, о которых нужно знать:

  1. Вам не нужно помещать кавычки вокруг заполнителя подстановки в строке формата. Когда метод создает предикат, он будет создавать абстрактное синтаксическое дерево объектов NSExpression и NSPredicate (в частности, NSComparisonPredicate и NSCompoundPredicate). Ваша строка будет помещена в NSExpression типа NSConstantValueExpressionType, что означает, что уже будет интерпретироваться как обычная строка. Размещение одинарных кавычек в строке формата фактически сделает ваш предикат нефункциональным.
  2. Вы не ограничены одним сравнением в предикате. Судя по его звукам, вы хотите иметь столько сравнений, сколько у вас есть «слов» в строке поиска (nameVar). В этом случае мы разобьем nameVar на составляющие его слова и создадим сравнение для каждого слова. Как только мы это сделаем, мы AND будем вместе создавать единый всеобъемлющий предикат. Код ниже делает именно это.

оригинальный ответ

Вы можете сделать это, построив свой собственный NSCompoundPredicate:

NSString *nameVar = ...; //ex: smith m
NSArray *names = ...; //ex: John Smith, Mary Smith

NSArray *terms = [nameVar componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSMutableArray *subpredicates = [NSMutableArray array];

for(NSString *term in terms) {
  if([term length] == 0) { continue; }
  NSPredicate *p = [NSPredicate predicateWithFormat:@"name contains[cd] %@", term];
  [subpredicates addObject:p];
}

NSPredicate *filter = [NSCompoundPredicate andPredicateWithSubpredicates:subpredicates];
[fetchController setPredicate:filter];

Предупреждение: набрано в браузере на моем iPhone.

...