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

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

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

Edit:

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

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

I w-en * t t-o the st * o * r * -e yes-ster * day.

Изменить 2:

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

  • Возьмите строку ввода от пользователя
  • Возьмите строку для поиска
  • Используйте регулярное выражение на основе строки поиска пользователя для поиска совпадений "содержит" в большем блоке текста. Регулярное выражение должно игнорировать гласные, как показано выше.

Изменить 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:

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

Изменить 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]?

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

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

Ответ 1

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

Как выясняется, 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];
  }          
}

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

Awesome!

Ответ 2

Иудейские гласные хорошо определены в Юникоде: Таблица символов и знаков на иврите

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

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