搜索NSString中的任何字符



我有以下代码来搜索NSString:

for (NSDictionary *obj in data) {
        NSString *objQuestion = [obj objectForKey:@"Question"];
        NSRange dataRange = [objQuestion rangeOfString:searchText options:NSCaseInsensitiveSearch];
        if (dataRange.location != NSNotFound) {
            [filteredData addObject:obj];
        }
    }

这很好,但有一个问题。如果objQuestion是:"绿-黄-红"并且我搜索"黄-绿-红",则对象将不会显示,因为我的搜索顺序不正确。

我该如何更改代码,以便无论我以何种顺序搜索单词,对象都会显示?

您应该将搜索文本分解为多个单词并搜索每个单词。

NSArray *wordArray= [searchText componentsSeparatedByString: @" "];
for (NSDictionary *obj in data) {
    NSString *objQuestion = [obj objectForKey:@"Question"];        
    BOOL present = NO;
    for (NSString *s in wordArray) {
        if (s) {                
            NSRange dataRange = [objQuestion rangeOfString:s options:NSCaseInsensitiveSearch];
            if (dataRange.location != NSNotFound) {
               present = YES;
            }
        } 
    }
    if (present) {
        [filteredData addObject:obj];
    }
}

所以你想基本上进行关键字搜索吗?我建议进行正则表达式搜索。其中单词可以按任何顺序排列。

像这样的东西。

(your|test|data)? *(your|test|data)? *(your|test|data)?

可以在NSRegularExpressoin 中使用

NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"(your|test|data)? *(your|test|data)? *(your|test|data)?" options:NSRegularExpressionCaseInsensitive error:&error];
int numMatches = [regex numberOfMatchesInString:searchString options:0 range:NSMakeRange(0, [searchString length])];];

这将以有效的方式匹配任何订单。

不确定regex是否适用于Obj C,因为我现在没有mac,但它应该可以。

您可能需要考虑搜索输入字符串并不总是像您期望的那样干净,并且可能包含标点符号、括号等。

你也会想放松口音。

我喜欢使用正则表达式来解决这类问题,因为您正在寻找一种允许对搜索词进行任意排序的解决方案,所以我们需要重新处理搜索字符串。我们也可以使用正则表达式来实现这一点,所以模式是通过正则表达式替换来构建的,这只是出于原则。您可能需要将其彻底记录下来。

因此,这里有一个代码片段可以做这些事情:

// Use the Posix locale as the lowest common denominator of locales to
// remove accents.
NSLocale *enLoc = [[NSLocale alloc] initWithLocaleIdentifier: @"en_US_POSIX"];
// Mixed bag of genres, but for testing purposes we get all the accents we need
NSString *orgString = @"Beyoncé Motörhead Händel"; 
// Clean string by removing accents and upper case letters in Posix encoding
NSString *string = [orgString stringByFoldingWithOptions: NSCaseInsensitiveSearch | NSDiacriticInsensitiveSearch
                                                  locale: enLoc ];
// What the user has typed in, with misplaced umlaut and all
NSString *orgSearchString = @"handel, mötorhead, beyonce";
// Clean the search string, too
NSString *searchString = [orgSearchString stringByFoldingWithOptions: NSCaseInsensitiveSearch | NSDiacriticInsensitiveSearch | NSWidthInsensitiveSearch
                                                              locale: enLoc ];
// Turn the search string into a regex pattern.
// Create a pattern that looks like: "(?=.*handel)(?=.*motorhead)(?=.*beyonce)"
// This pattern uses positive lookahead to create an AND logic that will
// accept arbitrary ordering of the words in the pattern.
// The b expression matches a word boundary, so gets rid of punctuation, etc.
// We use a regex to create the regex pattern.
NSString *regexifyPattern = @"(?w)(\W*)(\b.+?\b)(\W*)";
NSString *pattern = [searchString stringByReplacingOccurrencesOfString: regexifyPattern
                                                            withString: @"(?=.*$2)"
                                                               options: NSRegularExpressionSearch
                                                                 range: NSMakeRange(0, searchString.length) ];
NSError *error;
NSRegularExpression *anyOrderRegEx = [NSRegularExpression regularExpressionWithPattern: pattern
                                                                               options: 0
                                                                                 error: &error];
if ( !anyOrderRegEx ) {
    // Regex patterns are tricky, programmatically constructed ones even more.
    // So we check if it went well and do something intelligent if it didn't
    // ...
}
// Match the constructed pattern with the string
NSUInteger numberOfMatches = [anyOrderRegEx numberOfMatchesInString: string
                                                    options: 0
                                                      range: NSMakeRange(0, string.length)];

BOOL found = (numberOfMatches > 0);

Posix区域设置标识符的使用在Apple的技术说明中进行了讨论。

理论上,如果用户为正则表达式输入具有特殊含义的字符,则会出现边缘情况,但由于第一个正则表达式删除了非单词字符,因此应该以这种方式解决。有点未经计划的积极副作用,因此值得验证。

如果您对基于正则表达式的解决方案不感兴趣,那么代码折叠对于基于"正常"NSString的搜索可能仍然有用。

最新更新