Как использовать регулярные выражения для поиска, игнорируя определенные символы с NSPredicate? - PullRequest
11 голосов
/ 07 ноября 2011

На иврите есть определенные гласные, которые NSPredicate не может игнорировать, даже если в предикате используется модификатор d (нечувствительный к диакритике). Мне сказали, что решение - использовать регулярные выражения для поиска.

Как мне взять строку поиска и "использовать регулярные выражения" для поиска текста на иврите, который содержит гласные, игнорируя эти гласные?

Edit:

Другими словами, если бы я хотел найти следующий текст, не обращая внимания на тире и звездочки, как бы я сделал это с помощью регулярных выражений?

Пример текста:

Я хочу знать, что день ... день * день.

Редактировать 2:

По сути, я хочу:

  1. Взять входную строку у пользователя
  2. Возьмите строку для поиска
  3. Используйте регулярное выражение на основе строки поиска пользователя для поиска «содержащих» совпадений в большем блоке текста. Регулярное выражение должно игнорировать гласные, как показано выше.

Редактировать 3:

Вот как я реализую свой поиск:

//
//  The user updated the search text
//

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller 
shouldReloadTableForSearchString:(NSString *)searchString{

    NSMutableArray *unfilteredResults = [[[[self.fetchedResultsController sections] objectAtIndex:0] objects] mutableCopy];

    if (self.filteredArray == nil) {
        self.filteredArray = [[[NSMutableArray alloc ] init] autorelease];
    }

    [filteredArray removeAllObjects];

    NSPredicate *predicate;

    if (controller.searchBar.selectedScopeButtonIndex == 0) {
        predicate = [NSPredicate predicateWithFormat:@"articleTitle CONTAINS[cd] %@", searchString];
    }else if (controller.searchBar.selectedScopeButtonIndex == 1) {
        predicate = [NSPredicate predicateWithFormat:@"articleContent CONTAINS[cd] %@", searchString];            
    }else if (controller.searchBar.selectedScopeButtonIndex == 2){
        predicate = [NSPredicate predicateWithFormat:@"ANY tags.tagText CONTAINS[cd] %@", searchString];
    }else{
        predicate = [NSPredicate predicateWithFormat:@"(ANY tags.tagText CONTAINS[cd] %@) OR (dvarTorahTitle CONTAINS[cd] %@) OR (dvarTorahContent CONTAINS[cd] %@)", searchString,searchString,searchString];
    }

    for (Article *article in unfilteredResults) {

        if ([predicate evaluateWithObject:article]) {
            [self.filteredArray addObject:article];
        }

    }

    [unfilteredResults release];


    return YES;
}

Редактировать 4:

Я не обязан использовать регулярные выражения для этого, мне просто посоветовали это сделать. Если у вас есть другой способ, который работает, пойти на это!

Редактировать 5:

Я изменил свой поиск так:

NSInteger length = [searchString length];

NSString *vowelsAsRegex = @"[\\u5B0-\\u55C4]*";

NSMutableString *modifiedSearchString = [searchString mutableCopy];

for (int i = length; i > 0; i--) {
    [modifiedSearchString insertString:vowelsAsRegex atIndex:i];
}

if (controller.searchBar.selectedScopeButtonIndex == 0) {
            predicate = [NSPredicate predicateWithFormat:@"articleTitle CONTAINS[cd] %@", modifiedSearchString];
        }else if (controller.searchBar.selectedScopeButtonIndex == 1) {
            predicate = [NSPredicate predicateWithFormat:@"articleContent CONTAINS[cd] %@", modifiedSearchString];            
        }else if (controller.searchBar.selectedScopeButtonIndex == 2){
            predicate = [NSPredicate predicateWithFormat:@"ANY tags.tagText CONTAINS[cd] %@", modifiedSearchString];
        }else{
            predicate = [NSPredicate predicateWithFormat:@"(ANY tags.tagText CONTAINS[cd] %@) OR (dvarTorahTitle CONTAINS[cd] %@) OR (dvarTorahContent CONTAINS[cd] %@)", modifiedSearchString,modifiedSearchString,modifiedSearchString];
        }

for (Article *article in unfilteredResults) {
  if ([predicate evaluateWithObject:article]) {
    [self.filteredArray addObject:article];
  }          
 }

Я все еще что-то здесь упускаю, что мне нужно сделать, чтобы эта работа работала?

Редактировать 6:

Хорошо, почти там. Мне нужно сделать еще два изменения, чтобы закончить с этим.

Мне нужно иметь возможность добавлять другие диапазоны символов в регулярное выражение, которые могут появиться вместо или в дополнение к символу в другом наборе. Я пытаюсь изменить первый диапазон на это:

[\u05b0-\u05c, \u0591-\u05AF]?

Что-то подсказывает мне, что это неправильно.

Кроме того, мне нужно, чтобы остальные регулярные выражения были без учета регистра. Какой модификатор мне нужно использовать с .* регулярным выражением, чтобы сделать его нечувствительным к регистру?

Ответы [ 2 ]

2 голосов
/ 23 ноября 2011

Этот ответ начинается там, где вопрос остановился. Пожалуйста, прочитайте это для контекста.

Как оказалось, iOS может сделать регулярные выражения нечувствительными к регистру, используя модификатор Objective C для NSPredicate. Осталось только объединить два диапазона. Я понял, что это на самом деле два последовательных диапазона. Мой окончательный код выглядит так:

NSInteger length = [searchString length];

NSString *vowelsAsRegex = @"[\u0591-\u05c4]?[\u0591-\u05c4]?"; //Cantillation: \u0591-\u05AF Vowels: \u05b0-\u05c

NSMutableString *modifiedSearchString = [searchString mutableCopy];

for (int i = length; i > 0; i--) {
    [modifiedSearchString insertString:vowelsAsRegex atIndex:i];
}

if (controller.searchBar.selectedScopeButtonIndex == 0) {
  predicate = [NSPredicate predicateWithFormat:@"articleTitle CONTAINS[cd] %@", modifiedSearchString];
}else if (controller.searchBar.selectedScopeButtonIndex == 1) {
    predicate = [NSPredicate predicateWithFormat:@"articleContent CONTAINS[c] %@", modifiedSearchString];            
}else if (controller.searchBar.selectedScopeButtonIndex == 2){
    predicate = [NSPredicate predicateWithFormat:@"ANY tags.tagText CONTAINS[c] %@", modifiedSearchString];
}else{
    predicate = [NSPredicate predicateWithFormat:@"(ANY tags.tagText CONTAINS[c] %@) OR (dvarTorahTitle CONTAINS[c] %@) OR (dvarTorahContent CONTAINS[c] %@)", modifiedSearchString,modifiedSearchString,modifiedSearchString];
}

[modifiedSearchString release];

for (Article *article in unfilteredResults) {
  if ([predicate evaluateWithObject:article]) {
    [self.filteredArray addObject:article];
  }          
}

Обратите внимание, что часть диапазона регулярного выражения повторяется. Это потому, что на одной букве может быть как знак кантилляции, так и гласный. Теперь я могу искать заглавные и строчные буквы английского языка и иврита с гласными или без знаков гласности или без них.

Отлично!

2 голосов
/ 21 ноября 2011

Гласные на иврите четко определены в Unicode: Таблица символов и знаков иврита

Когда вы получаете входную строку от пользователя, вы можете вставить регулярное выражение [\u05B0-\u05C4]* между каждым символом, и до и после строки. (Средство [] соответствует любому из включенных символов, а средство * соответствует нулю или большему количеству вхождений выражения.) Затем можно выполнить поиск в текстовом блоке, используя это как регулярное выражение. Это выражение позволяет вам найти точную строку из ввода пользователя. Пользователь также может указать необходимые гласные, которые найдет это выражение.

Я думаю, что вместо того, чтобы пытаться "игнорировать" гласные, было бы легче удалить гласные как из большого блока текста, так и из строки пользователя. Тогда вы можете искать только буквы, как обычно. Этот метод будет работать, если вам не нужно отображать вокализованный текст, найденный пользователем.

...