Reid
Reid

Reputation: 1129

iOS app searching large amounts of text

I apologize if this is a repeat, but I honestly have done my best to research this and haven't come up with much.

I'm making an iPad reference app that will make several large textbooks searchable (maybe 3-4k pages in total). It's a fairly simple idea: the user can choose any combination of texts to search, put in his term, and the app will find those terms in all the texts and return them, indexed in a table view.

The view controller has a series of switches, the value of which get read by a method into an NSSet and passed to the search controller. That part works.

I have a SearchController class which the view controller instantiates and calls a method on:

-(void)performSearchWithString:(NSString *)searchString andTexts:(NSSet *)texts
{
for (id book in texts) {
    if ([book isEqual:kBook1]){
        NSError *error = nil;
        NSURL *url = [[NSBundle mainBundle] URLForResource:@"neiJing" withExtension:@"txt"];
        NSString *text = [NSString stringWithContentsOfURL:url encoding:NSStringEncodingConversionAllowLossy error:&error];
        [text enumerateSubstringsInRange:NSMakeRange(0, [text length])
                                 options:NSStringEnumerationByWords
                              usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
                                  NSRange found = [substring rangeOfString:text];
                                  if (found.location != NSNotFound) {
                                      NSLog(@"%@", substring);
                                  } else {
                                      NSLog(@"Not found");
                                  }
                              }];
    }

I seem to have succeeded in enumerating through every word in all the texts, but no return values are found so I just get a never-ending stream of "Not found".

I inserted a test phrase into each text that I know for certain to be there, but it's not coming up.

I have a feeling I'm going about this all wrong. Even if I made this work, the performance hit might be too big for a useable app...I'm still trying to wrap my head around blocks, too. I just haven't found any ready-baked solutions out there for searching large volumes of text and picking out results. If anyone has any hints or references to an open-source library that I might adapt, I would be very grateful.

Upvotes: 3

Views: 262

Answers (2)

Jeffery Thomas
Jeffery Thomas

Reputation: 42588

I don't think the block of code is what you want. It loops through each word in the text and you want to find all the search strings. Here is a loop that sets a new search range based on the last successful match.

-(void)performSearchWithString:(NSString *)searchString andTexts:(NSSet *)texts
{
for (id book in texts) {
    if ([book isEqual:kBook1]){
        NSError *error = nil;
        NSURL *url = [[NSBundle mainBundle] URLForResource:@"neiJing" withExtension:@"txt"];
        NSString *text = [NSString stringWithContentsOfURL:url encoding:NSStringEncodingConversionAllowLossy error:&error];

        NSRange searchRange = NSMakeRange(0, [text length]);
        NSRange match = [text rangeOfString:searchString options:0 range:searchRange];
        while (match.location != NSNotFound) {

            // match is the range of the current successful match
            NSLog(@"matching range -- %@", NSStringFromRange(match));

            NSUInteger locationOfNextSearchRange = NSMaxRange(match);
            searchRange = NSMakeRange(locationOfNextSearchRange, [text length] - locationOfNextSearchRange);
            match = [text rangeOfString:searchString options:0 range:searchRange];
        }
    }
}

Upvotes: 1

danh
danh

Reputation: 62686

It looks like you're searching for the whole text inside of each substring passed to the block. This line is the problem (and causes a retain cycle):

NSRange found = [substring rangeOfString:text];

The code needs to look for something it can find:

NSString *findMe = @"A string we expect to find";        
[text enumerateSubstringsInRange:NSMakeRange(0, [text length])
                         options:NSStringEnumerationByWords
                      usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
                                  if ([findMe isEqualToString:substring] ) {
                                      NSLog(@"Found %@", substring);
                                  } else {
                                      NSLog(@"Not found");
                                  }
                              }];

Upvotes: 2

Related Questions