Границы слова (\ b) в NSPredicate, в результате чего NSFetchRequest не возвращает управляемые объекты - PullRequest
1 голос
/ 19 мая 2010

Использование базовых данных с хранилищем sqlite на iPhone .... У меня есть набор сущностей с изображениями комиксов, каждая со строкой, которая включает в себя номер комикса #, например: image.imageTitle = @"Issue 12: Special Edition";

Часть пользовательского интерфейса позволяет пользователю ввести номер проблемы, чтобы перейти к следующей проблеме. Мой исходный код для этого был sloooooooow, потому что imageAtIndex: запрашивает базовые данные для одного объекта за один раз. Более нескольких сотен проблем может пройти более 40 секунд, чтобы пройти первый цикл!

Медленный код:

 // Seek forward from the next page to the right
 for (i = currentPage + 1; i < [self numberOfPages]; i++) {
  iterationString = [[self imageAtIndex:i] imageTitle];
  iterationNumber = [[iterationString stringByTrimmingCharactersInSet:nonDigits] intValue];

  if (issueNumber == iterationNumber) {
   keepLooking = NO;
   break;
  }
 }
 // If nothing was found to the right, seek forward from 0 to the current page
 if (i == [self numberOfPages] && keepLooking) {
  for (i = 0 ; i < currentPage; i++) {
   iterationString = [[self imageAtIndex:i] imageTitle];
   iterationNumber = [[iterationString stringByTrimmingCharactersInSet:nonDigits] intValue];

   if (issueNumber == iterationNumber) {
    keepLooking = NO;
    break;
   }
  }
 }

Надеясь на гораздо более эффективное решение, я решил попытаться сделать прямой запрос к Базовым данным следующим образом:

    NSString *issueNumber = @"12";
    NSString *issueWithWordBoundaries = [NSString stringWithFormat:@"\\b%@\\b",issueNumber];
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(groupID == %@) AND (imageTitle CONTAINS %@)", groupID, issueWithWordBoundaries];

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
 NSEntityDescription *entity = [NSEntityDescription entityForName:@"CBImage" inManagedObjectContext:self.managedObjectContext];
 [fetchRequest setEntity:entity];

 [fetchRequest setPredicate:predicate];
 [fetchRequest setIncludesSubentities:NO]; // Not sure if this is needed, but just in case....

 // Execute the fetch
 NSError *error = nil;
 NSArray *fetchedObjects = [managedObjectContext executeFetchRequest:fetchRequest error:&error];

    // [fetchedImages count] == 0

Между Руководством по программированию предикатов и Спецификациями регулярного выражения ICU я полагал, что \ b поможет предотвратить поиск 12, возвращающий 120, 121, 122 и т. Д. Вместо этого он вообще ничего не возвращает из магазина!

С другой стороны, если я опускаю границы слова и вместо этого ищу stringWithFormat:@"%@",issueNumber, я получаю десятки возвращаемых управляемых объектов, от 12 до 129 до 412.

Мое лучшее предположение на данный момент заключается в том, что я столкнулся с одним из ограничений и ограничений Core Data . Если нет, что я делаю не так? Если да, есть ли обходной путь, который предлагает как точное совпадение , так и скорость одной выборки?

Ответы [ 2 ]

3 голосов
/ 19 мая 2010

\b относится к символу возврата. Попробуйте

[NSString stringWithFormat:@"\\b%@\\b",issueNumber];
//                           ^^   ^^

И чтобы выполнить соответствие RegEx, используйте MATCHES, а не CONTAINS.

1 голос
/ 22 мая 2010

Оказывается, что границы слов были красной сельдью: моя проблема была в варианте этой проблемы : регулярное выражение не могло быть успешным без каких-либо подстановочных знаков, совпадающих с битами, которые меня не волновали в imageTitles.

Таким образом, общее решение для нахождения точной фразы с использованием NSPredicate:

NSString *exactPhrase = @"phrase_you_hope_to_find_in_another_string";
NSString *regularExpression = [NSString stringWithFormat:@".*\\b%@\\b.*",exactPhrase];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"stringToSearch CONTAINS %@", exactPhrase];
// Assuming a string or an entity's string attribute named stringToSearch
...