Objective c - 按单词搜索

Posted

技术标签:

【中文标题】Objective c - 按单词搜索【英文标题】:Objective c - search by word 【发布时间】:2014-08-03 09:32:25 【问题描述】:

我有一个图书应用,用户可以在其中浏览和搜索图书。 例如这是书籍列表:

“腐肉舒适” “遮住她的脸” “老人无国” 《猴子的雨衣》

我想实现一个行为如下的搜索机制: 如果用户搜索“co”,结果将是:

“Carrion Comfort” “认识她的脸” “老人没有合作

你可以注意到我只想找到以“co”开头的单词,这就是为什么“猴子的雨衣”这本书虽然包含“co”却不在结果中

为此,我创建了一个名为 Token 的托管对象:

Token  
------
normalizedString  

我在 Book 对象中添加了一对多关系

Book
-----
title  
releaseDate

tokens (to-many)  

现在这就是我的搜索谓词的样子:

[NSPredicate predicateWithFormat:@"SUBQUERY(tokens, $token, $token.normalizedString BEGINSWITH[cd] %@).@count > 0", [searchString lowercaseString]];  

如果我搜索单个单词,这很好用,例如,如果我搜索“她”,我会得到结果: “捂脸”

但是当我尝试搜索多个单词时,例如“她的脸”,我没有得到任何结果。

我明白为什么会发生这种情况,但在这里找不到正确的解决方案。 任何帮助将不胜感激

【问题讨论】:

您显然想要的是 KWIK 索引。 (查一下。应该有几种算法被提出。) 在我看来,当你应该使用两块石头时,你却试图用同一块石头击中两只鸟。当您的用户点击空间时,您不再需要检查前缀,而只需要检查包含? 【参考方案1】:

我猜这是一个骇人听闻的解决方案,但我会尝试以不同的方式生成令牌。 记号不仅仅是一个词,而是从一个词开始并包含以下文本。

为了“遮住她的脸”

代替

Cover
Her
Face

我会尝试获取令牌:

Cover Her Face
Her Face
Face

然后,BEGINSWITH 解决方案应该按您的预期工作。这对你有意义吗?

【讨论】:

【参考方案2】:

假设您将书籍存储在 NSString*s 的 NSArray/NSMutableArray...(抱歉,我不知道 NSPredicate 是什么。但是如果您能够将书籍转换为 @ 987654325@s 那你可以用这个方法)

NSMutableArray* books = [NSMutableArray arrayWithObjects:   @"Carrion Comfort",
                                                            @"Cover Her Face",
                                                            @"No Country for Old Men",
                                                            @"The Monkey's Raincoat",
                                                            nil ];

[books enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) 
    NSArray* _tmp = [(NSString*)obj componentsSeparatedByString:@" "];
    [_tmp enumerateObjectsUsingBlock:^(id _obj, NSUInteger idx, BOOL *stop) 
        if ([[_obj substringToIndex:2] isEqualTo:@"co"] ||
            [[_obj substringToIndex:2] isEqualTo:@"Co"])
            NSLog(@"%@", obj);
    ];
];

这可能不是最有效的方法,但绝对有效。

除了提供所有可能的变化之外,必须有一种方法来处理区分大小写,但我真的没有时间弄清楚。也许在比较之前将所有内容都转换为小写?

【讨论】:

【参考方案3】:

为了回答我自己的问题,我最终对搜索字符串进行了标记,并创建了一个更复杂的谓词来处理这些标记:

- (NSPredicate *)predicateForSearchString:(NSString *)searchString     
    NSSet *searchTokens = [[Tokenizer sharedTokenizer] tokenize:searchString];

    NSMutableArray *subPreds = [NSMutableArray arrayWithCapacity:searchTokens.count];
    for (NSString *token in searchTokens) 
        NSPredicate *pred = [NSPredicate predicateWithFormat:@"SUBQUERY(tokens, $token, $token.normalizedString BEGINSWITH[cd] %@).@count > 0", token];
        [subPreds addObject:pred];
    
    return [NSCompoundPredicate andPredicateWithSubpredicates:[subPreds copy]];

【讨论】:

以上是关于Objective c - 按单词搜索的主要内容,如果未能解决你的问题,请参考以下文章

IOS/Objective-C:按字符串中的单词数对 NSStrings 的 NSArray 进行排序

在 Objective C 中搜索函数

来自Objective c中数组项的自动完成文本字段

在Objective C中按顺序保持JSON对象的字典键

Objective C中的两个数组中的字符串搜索

如何在 OBJECTIVE C 的 UITableViewCell 中更改先前按下的 UIButton 标签?