NSPredicate, който игнорира запетаи?

Приложих UISearchDisplayController, който позволява на потребителите да търсят в таблица. В момента предикатът, който използвам за търсене, е следният,

NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:@"Name contains[cd] %@", searchText];

Сега да кажем, че потребител търси „боб, варен“, съответните съвпадения се намират в таблицата. Но ако потребителят въведе текста за търсене като "варен боб" без запетаята, няма да бъдат намерени съвпадения.

Как мога да пренапиша своя предикат, за да "игнорирам" запетаите при търсене? С други думи, как мога да го пренапиша, така че да вижда, че „боб, варен“ е равен на „боб, варен“ (БЕЗ ЗАПЕЯТА)?


person gossainapps    schedule 15.06.2012    source източник
comment
Ако всичко, което искате да направите, е да премахнете запетаите, тогава searchText = [searchText stringByTrimmingCharactersInSet:characterSet] или searchText = [searchText stringByReplacingOccurrencesOfString:@"," withString:@""] трябва да направят.   -  person cdelacroix    schedule 16.06.2012
comment
Благодаря, но проблемът ми всъщност е, че запетаята всъщност не е само в думата за търсене, но може да е и в ключа (в случая @Name), който се търси. И така, има ли начин да търсим, като игнорираме препинателните знаци, точно както можем да търсим, като игнорираме главни и малки букви?   -  person gossainapps    schedule 16.06.2012
comment
Добре, бихте искали пълнофункционална търсачка, нямате проблем само със запетаята. Може би бихте искали търсенето Варен боб да върне същия резултат, а също и Варен боб, и може би варен боб, а защо не и печен боб. Начинът, който трябва да направите, е да токенизирате записа, да филтрирате празните думи и да създадете сложна заявка. Разбира се, тези действия са специфични за езика. Преди няколко години направих всичко на ръка, сега съм любопитен дали някой ще спомене добра библиотека на трета страна, която да свърши работата.   -  person cdelacroix    schedule 16.06.2012
comment
Да, така е, бих искал търсенето да е по-лесно за потребителя. Успях да постигна това, като актуализирах моята база данни с нов ключ, който съдържа същото име, но с премахнати всички препинателни знаци, запетаи и т.н. Така че сега мога също да търся този нормализиран ключ едновременно. Не е перфектно, но е много по-добро и беше сравнително лесно за изпълнение. Благодаря много за отговора!   -  person gossainapps    schedule 16.06.2012


Отговори (3)


Първо отказ от отговорност:

Мисля, че това, което се опитвате да направите, е да добавите известна "размитост" към вашия алгоритъм за търсене, виждайки, че искате да направите вашето съвпадение нечувствително към определени разлики в потребителското въвеждане.

Предикатите (които са логически конструкции) по своята същност не са размити, така че има основно несъответствие на импеданса между проблема и избрания инструмент.

Както и да е, един от начините да го направите може да бъде да добавите метод към вашия модел обектен клас.

При този метод можете да изчистите низа на името си, така че да съдържа само най-основните знаци, да речем числа, ASCII букви и интервал.

Тъй като е напълно детерминиран, такъв метод е ефективно свойство на низ само за четене на вашия обект и като такъв може да се използва за съпоставяне в предикати.

Ето една реализация, която премахва пунктуацията, ударенията и диакритичните знаци:

- (NSString *)simplifiedName
{
    // First convert the name string to a pure ASCII string
    NSData *asciiData = [self.name dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];

    NSString *asciiString = [[[NSString alloc] initWithData:asciiData encoding:NSASCIIStringEncoding] lowercaseString];

    // Define the characters that we will allow in our simplified name
    NSString *searchCharacters = @"0123456789 abcdefghijklmnopqrstuvwxyz";

    // Remove anything else
    NSString *regExPattern = [NSString stringWithFormat:@"[^%@]", searchCharacters];

    NSString *simplifiedName = [asciiString stringByReplacingOccurrencesOfString:regExPattern withString:@"" options:NSRegularExpressionSearch range:NSMakeRange(0, asciiString.length)];

    return simplifiedName;
}

Сега може да се направи предикат за търсене в опростеното име:

NSPredicate *pred = [NSPredicate predicateWithFormat:@"self.simplifiedName = %@", searchString];

Вие, разбира се, бихте искали да почистите низа за търсене, като използвате същия алгоритъм, използван за почистване на името, така че вероятно би било добра идея да го включите в общ метод, който да се използва и на двете места.

И накрая, методът simplifiedName може също да бъде добавен чрез внедряване на категория към класа на моделния обект, така че да не се налага да модифицирате неговия код, което е удобно в случай, че вашият клас на обект е дефиниран в автоматично генериран файл от Core Data.

person Monolo    schedule 17.06.2012
comment
изглежда self.simplifiedName не е начин за CoreData. Някакви мисли как да направите този трик с Core Data? - person beryllium; 24.09.2014

Това може да е малко хакерско, но можете просто да премахнете запетаята от думата за търсене.

Пример:

searchText = [searchText stringByReplacingOccurrencesOfString:@"," withString:@""];
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:@"Name contains[cd] %@", searchText];
person Chance Hudson    schedule 15.06.2012
comment
Здравейте, благодаря за отговора, но проблемът ми е, че запетаята всъщност не е само в термина за търсене, но е и в ключа (в случая @Name), който се търси. - person gossainapps; 16.06.2012

Най-доброто решение, което намерих за този тип проблем, е всъщност да добавя запис във всеки речник на елементи, който има същото име, но ще премахне всички препинателни знаци, запетаи, тирета и т.н., както в този отговор

person gossainapps    schedule 16.06.2012