如何使用正则表达式搜索忽略 NSPredicate 的某些字符?

Posted

技术标签:

【中文标题】如何使用正则表达式搜索忽略 NSPredicate 的某些字符?【英文标题】:How do I use regex to search ignoring certain characters with NSPredicate? 【发布时间】:2011-11-07 03:26:00 【问题描述】:

在希伯来语中,NSPredicate 无法忽略某些元音,即使在谓词中使用“d”(变音符号不敏感)修饰符也是如此。有人告诉我,解决方案是使用正则表达式进行搜索。

如何获取搜索字符串并“使用正则表达式”来搜索包含元音的希伯来文文本,而忽略这些元音?

编辑:

换句话说,如果我想搜索以下文本,不考虑破折号和星号,我将如何使用正则表达式?

示例文字:

我 w-en*t t-o 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:

我不需要为此使用正则表达式,只是建议这样做。如果您有其他可行的方法,那就去吧!

编辑 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]?

有些东西告诉我这是不正确的。

另外,我需要正则表达式的其余部分不区分大小写。我需要在 .* 正则表达式中使用什么修饰符才能使其不区分大小写?

【问题讨论】:

NSPredicate and Regex的可能重复 可能是: 1. 删除坏符号(元音)。 2. 添加类似这样的内容:“.*?”在每个字符之后。 3. 搜索。你会接受这样的决定吗? 【参考方案1】:

希伯来语元音在 Unicode 中定义明确:Table of Hebrew characters and Marks

当您收到用户输入的字符串时,您可以在每个字符之间以及字符串的前后插入正则表达式[\u05B0-\u05C4]*。 ([] 表示匹配任何包含的字符,* 表示匹配零次或多次出现的表达式。)然后您可以搜索文本块,将其用作正则表达式。此表达式允许您从用户输入中找到确切的字符串。用户还可以指定所需的元音,该表达式会找到这些元音。

我认为与其尝试“忽略”元音,不如从大文本块和用户字符串中删除元音会更容易。然后你可以像往常一样只搜索字母。如果您不需要显示用户找到的有声文本,则此方法会起作用。

【讨论】:

看起来是个好主意。将搜索字符串转换为正则表达式的有效方法是什么? @Moshe,我不知道什么是有效(甚至是好)的方法。您可以使用NSMutableStringinsertString:atIndex:,我想从字符串末尾开始循环倒计时。不过,我不知道这是否很好。 我有一个可行的解决方案,这很有帮助,当我在电脑前时会有更多。 你引导我找到我自己的答案,有赏金!【参考方案2】:

这个答案从问题停止的地方开始。请阅读上下文。

事实证明,ios 可以使用 NSPredicate 的 Objective-C 修饰符使正则表达式不区分大小写。剩下的就是结合这两个范围。我意识到它们实际上是两个连续的范围。我的最终代码如下所示:

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];
            

请注意,正则表达式的范围部分会重复。这是因为单个字母上可以同时有一个cantillation mark 和一个元音。现在,我可以搜索大写和小写的英语,以及带有或不带有元音和音标的希伯来语。

太棒了!

【讨论】:

很高兴您找到了答案。我没有意识到您也在搜索英文文本或带有cantillation 的希伯来文。也就是说,我感觉您没有 100% 的解决方案。举个例子诗句 על פני המים。 “מ”有元音、标记和达格什。那是 3,但你只允许 2。另外,我不确定以元音开头的字符串是否是有效的 Unicode,但如果是,你不要去掉它。 好点。您认为值得在正则表达式字符串中添加第三个字符吗?有没有办法指定“零次或多次,最多三次”? 我建议像以前一样使用*,但我认为0,3 也可以工作0 到3 次——不确定你是否可以将0 与 一起使用。跨度>

以上是关于如何使用正则表达式搜索忽略 NSPredicate 的某些字符?的主要内容,如果未能解决你的问题,请参考以下文章

如何忽略正则表达式主题字符串中的空格?

在 NSPredicate 中使用带有 ISBN 数字示例的正则表达式令人困惑

iOS小技能:NSPredicate在正则表达式的应用下篇

NSPredicate 和正则表达式

搜索正则表达式时忽略子节点

通过系统自带的NSPredicate使用正则表达式