1

我得到了UITextView一个任意长度的文本(最多 10000 个字符)。我需要解析此文本,提取所有关键字并按使用频率列出它们,最常用的单词在最上面,下一个,等等。我很可能会在操作完成后呈现一个模态 UITableView。

我正在考虑一种有效且有用的方法来做到这一点。我可以尝试使用 [空格、标点符号等] 形式的分隔符来分隔字符串。这给了我一个字符序列数组。我可以将每个添加序列添加为一个NSMutableDictionary键,并在我看到该单词的另一个实例时增加它的计数。但是,这可能会导致 300-400 个单词的列表,其中大多数的频率为 1。

有没有一种好方法来实现我所描述的逻辑?我应该尝试按字母顺序对数组进行排序并尝试某种“模糊”逻辑匹配吗?是否有任何 NSDataDetector 或 NSString 方法可以为我做这种工作?

另一个问题是:我如何提取诸如 a、at、to、for 等内容,并且不将它们列在我的关键字列表中?

如果我可以看一下已经完成此任务的示例项目,那就太好了。

谢谢!

4

3 回答 3

2

您可以使用CFStringTokenizer来获取单词边界。对于计数,您可以NSMutableDictionary按照您的建议使用 或NSCountedSet,这可能会更有效。

如果您对频率为 1(或其他阈值)的单词不感兴趣,则必须在计算完所有单词后将它们过滤掉。

要忽略某些单词(a、the、for...),您需要一个特定于文本语言的单词列表。维基百科关于停用词的文章包含几个链接,例如这个 CSV 文件

于 2012-04-22T14:54:24.167 回答
2

有很多方法可以做到这一点。

您绝对应该将所有关键字添加到数组(或其他集合对象)并引用它/遍历它,以便您搜索这些关键字并且仅搜索这些关键字(并且避免检查 a、at、to、for、 ETC。)

NSArray *keywords = [ add your keywords ];

NSString *textToSearchThrough = @" your text ";  // or load your text File here

- loop control statement here (like maybe fast enumerate), and inside this loop:
NSRange range = [textToCheckThrough rangeOfString:keywords[currentKeyword] 
                              options:NSCaseInsensitiveSearch];
if(range.location != NSNotFound) {
   // meaning, you did find it 
   // add it to a resultsArray, add 1 to this keyword's occurrenceCounter (which you must also declare and keep track of)
   // etc.
}

然后你遍历你的结果数组,检查每个关键字的出现次数,清除那些出现次数小于 minOccurrenceCount 的人,然后从最高到最低排序剩余的。

于 2012-04-22T15:11:42.743 回答
0

我最终选择了CFStringTokenizer. 我不确定下面的桥接演员表是否正确,但它似乎有效

-(void)listAllKeywordsInString:(NSString*)text
    {
        if(text!=nil)
        {
            NSMutableDictionary* keywordsDictionary = [[NSMutableDictionary alloc] initWithCapacity:1024];
            NSString* key = nil;
            NSLog(@"%@",text);

             NSLog(@"Started parsing: %@",[[NSDate date] description]);

            CFStringRef string =(__bridge CFStringRef)text; // Get string from somewhere

        CFStringTokenizerRef tokenizer = CFStringTokenizerCreate(kCFAllocatorDefault,  (__bridge_retained CFStringRef) text, CFRangeMake (0,CFStringGetLength((__bridge_retained CFStringRef)text)), kCFStringTokenizerUnitWord, CFLocaleCopyCurrent());

            unsigned tokensFound = 0; // or the desired number of tokens

            CFStringTokenizerTokenType tokenType = kCFStringTokenizerTokenNone;

            while(kCFStringTokenizerTokenNone != (tokenType = CFStringTokenizerAdvanceToNextToken(tokenizer)) ) {
                CFRange tokenRange = CFStringTokenizerGetCurrentTokenRange(tokenizer);
                CFStringRef tokenValue = CFStringCreateWithSubstring(kCFAllocatorDefault, string, tokenRange);

                // This is the found word
                key =(__bridge NSString*)tokenValue;

                //increment its count
                NSNumber* count = [keywordsDictionary objectForKey:key];
                if(count!=nil)
                {
                     [keywordsDictionary setValue:[NSNumber numberWithInt:1] forKey:key];
                }else {
                    [keywordsDictionary setValue:[NSNumber numberWithInt:count.intValue+1] forKey:key];
                }



                CFRelease(tokenValue);

                ++tokensFound;
            }
            NSLog(@"Ended parsing. tokens Found: %d, %@",tokensFound,[[NSDate date] description]);
            NSLog(@"%@",[keywordsDictionary description]);
            // Clean up
            CFRelease(tokenizer);

        }


    }
于 2012-04-23T11:41:05.850 回答