如何在ios中搜索输入字符串中的所有单词?

时间:2015-07-20 21:44:33

标签: ios search recursion filter nspredicate

说,我有词汇量(大约100000个单词)和单词(“inputstring”)。所以:

我需要生成“inputstring”中的所有单词,如“input”,“string”,“put”,“strinpg”等。然后我需要在我的词汇表中查看它们。你能说出任何好的算法吗?因为我只知道:

  1. 在步骤1中递归搜索所有可能的组合
  2. 使用NSPredicates在我的词汇表中过滤它们。

5 个答案:

答案 0 :(得分:5)

我尝试使用NSRegularExpression,因为CoreData& NSPredicate似乎管理它们,但我没有一个可行的解决方案(可能与我在Regex中没有专业知识有关,但可能是一个领导者)。我也尝试使用NSCharacterSet,但它不能说出现次数是正确的。

这可能不是更性感的方式,但是,在这里你可以做什么:

NSString *searchedWord = @"inputString";

NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(NSString *evaluatedObject, NSDictionary *bindings) {
    for (NSUInteger index = 0; index < [evaluatedObject length]; index++)
    {
        NSString *subString = [evaluatedObject substringWithRange:NSMakeRange(index, 1)];

        NSUInteger numberOfOccurrencesInSearchWord = [self occurrencesOfSubString:subString inString:searchedWord];
        NSUInteger numberOfOccurrencesInCurrentWord = [self occurrencesOfSubString:subString inString:evaluatedObject];
        if (numberOfOccurrencesInCurrentWord > numberOfOccurrencesInSearchWord)
            return FALSE;
    }
    return TRUE;
}];

//Apply this predicate to your fetch

我在课程中添加了occurrencesOfSubString:inString:,但它可能是NSString上的类别。如果您愿意rangeOfString:option:range,也可以使用NSRegularExpression循环播放。 Source of the code(稍加修改)

-(NSUInteger)occurrencesOfSubString:(NSString *)subString inString:(NSString *)string
{
    NSUInteger numberOfMatches = 0;
    NSError *error = nil;
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:subString
                                                                           options:NSRegularExpressionCaseInsensitive error:&error];


    if (!error)
        numberOfMatches = [regex numberOfMatchesInString:string options:0 range:NSMakeRange(0, [string length])];

    return numberOfMatches;
}

注意:为避免过多循环,您可能需要删除evaluatedObject以便不检查重复值。 例如,如果evaluatedObject = @"aaa",则“a”将显示3次。因此,删除其中的重复值可能会提高速度。这是一个solution。 所以代码将在谓词块中:

NSString *evaluatedWithoutRepeat = [evaluatedObject removeDuplicatedCharacters];
for (NSUInteger index = 0; index <= [evaluatedWithoutRepeat length]; index ++)
{
    NSString *subString = [evaluatedWithoutRepeat substringWithRange:NSMakeRange:(index,1)];
    //The rest would be the same.
}

WorkingTest:

NSArray *testValues = @[@"inputString",
                        @"input",
                        @"string",
                        @"put",
                        @"strinpg",
                        @"Stringpg",
                        @"stringNOTWANTED"];
NSLog(@"AllValues: %@", testValues);

NSLog(@"Test: %@", [testValues filteredArrayUsingPredicate:predicate]);

输出:

> AllValues: (
    inputString,
    input,
    string,
    put,
    strinpg,
    Stringpg,
    stringNOTWANTED
)
> Test: (
    inputString,
    input,
    string,
    put,
    strinpg
)

答案 1 :(得分:3)

听起来你想把你的词汇表插入一个特里。这将为您提供一个数据结构,然后您可以快速检查以查找输入中存在于词汇表中的所有子字符串。

假设您正在构建一次trie并检查许多不同的输入字符串,这比通过组合查找输入的所有子字符串开始要快得多。 (这个速度是以特里的记忆为代价的。)

答案 2 :(得分:3)

您使用NSPredicate走在正确的轨道上。您正在寻找的阶段是fault tolerant搜索,并由Levenshtein distance解决。您基本上需要做的是在单个查询中对查询进行||组合。

假设您在NSArray中拥有所有单词。你需要在它上面调用方法filteredArrayUsingPredicate:,但是构建这样的谓词并不容易。

所以你的要求是:

  1. 搜索字词可以是较大字词的一部分
  2. 用户可以拼写错误的字词
  3. 第一部分非常简单,您需要做的就是将CONTAINS放到谓词中。第二部分应该像?tring or s?ring or st?ing...一样,可以使用简单的for轻松构建。您可以尝试使用各种数量的?符号,并查看符合条件的符号。

答案 3 :(得分:0)

我不确定是否有特殊的算法来解决您的问题。但是如果你必须用Core Data Fetch Requests来解决它,那么可能性是有限的。我会这样做:

- (NSArray *)getWordsFromString:(NSString *)input{

   NSMutableArray *result = [NSMutableArray new];
   NSUInteger *startIndex = 0;

   for (NSUInteger i = 0; i < input.length ; i++){
       NSString *substring = [input substringWithRange:NSMakeRange(*startIndex, i)];

      NSPredicate *predicate = [NSPredicate predicateWithFormat:@"word == %@", substring]; 
      NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Word"];
      fetchRequest.predicate = predicate
      [fetchRequest setIncludesPropertyValues:NO];
      [fetchRequest setIncludesSubentities:NO];
      NSArray *fetchResult = fetch result with predicate

       if (fetchResult.count > 0){
           [result addObject:substring];
           startIndex = i;
       }
   } 

   return result;
}

答案 4 :(得分:0)

NSMutableArray *foundWords = [NSMutableArray new];
for (NSString *knownWord in vocabulary)
{
    if ([input rangeOfString:knownWord].location != NSNotFound)
    {
        [foundWords addObject:knownWord];
    }
}

你可以通过准备词汇来实现。您应该只包含以输入字包含的字母开头的单词。