iosobjective-cnsstringnsscanner

Objective-c Line breaks every 23 characters without breaking words


I found this algorithm from this post Objective-c Line breaks every 10 characters (Keeping words in tact) the problem is that it never returns the last word it always discards it somehow.

NSString *sourceStr = @"The Chocholate Experience in the Anna Ice Cream Museum - Spanish";

NSMutableString *resultString = [[NSMutableString alloc] init];
NSMutableString *currentLine = [[NSMutableString alloc] init];
NSMutableArray *stringsArray = [[NSMutableArray alloc] init];
NSScanner *scanner = [NSScanner scannerWithString:sourceStr];
NSString *scannedString = nil;

while ([scanner scanUpToCharactersFromSet:[NSCharacterSet whitespaceCharacterSet] intoString: &scannedString]) {
    if ([currentLine length] + [scannedString length] <= 23) {
        [currentLine appendFormat:@"%@ ", scannedString];
    }
    else if ([currentLine length] == 0) { // Newline but next word > 23
        [resultString appendFormat:@"%@\n", scannedString];
    }
    else { // Need to break line and start new one
        [resultString appendFormat:@"%@\n", currentLine];
        [currentLine setString:[NSString stringWithFormat:@"%@ ", scannedString]];
    }
    [scanner scanCharactersFromSet:[NSCharacterSet whitespaceCharacterSet] intoString:NULL];
}
NSLog(@"Result String: \n%@", resultString);

I get this as the output: 
The Chocholate 
Experience in the Anna 
Ice Cream Museum -

gets rid of the last word which is Spanish. Anyone can see the bug? I've been at this for hours now. Any help would be greatly appreciated


Solution

  • If you step through, you'll notice that the word you're missing is stored in the currentLine var after when you're outside of the while loop. Basically that last else condition appends the "Ice Cream Museum -" to the resultString, but because there isn't anything else to scan ("Spanish" is already being held in scannedString -- so it's already been scanned), it just places the word "Spanish" in the current line and doesn't go through another iteration of the while loop (hence never placing it in the resultString to be printed out).

    Here's the modified code that should print out the last word:

    NSString *sourceStr = @"The Chocholate Experience in the Anna Ice Cream Museum - Spanish";
    
    NSMutableString *resultString = [[NSMutableString alloc] init];
    NSMutableString *currentLine = [[NSMutableString alloc] init];
    NSMutableArray *stringsArray = [[NSMutableArray alloc] init];
    NSScanner *scanner = [NSScanner scannerWithString:sourceStr];
    NSString *scannedString = nil;
    
    while ([scanner scanUpToCharactersFromSet:[NSCharacterSet whitespaceCharacterSet] intoString: &scannedString]) {
    
        // keep appending as long as we have something to append to
        if ([currentLine length] + [scannedString length] <= 23) {
            [currentLine appendFormat:@"%@ ", scannedString];
        }
        else if ([currentLine length] == 0) { // Newline but next word > 23
            [resultString appendFormat:@"%@\n", scannedString];
        }
        else { // Need to break line and start new one
            [resultString appendFormat:@"%@\n", currentLine];
            [currentLine setString:[NSString stringWithFormat:@"%@ ", scannedString]];
        }
        [scanner scanCharactersFromSet:[NSCharacterSet whitespaceCharacterSet] intoString:NULL];
    }
    // we may have something left over that couldn't fit into the last line
    // that needs to be appended to the result string
    if (currentLine.length > 0) {
        [resultString appendFormat:@"%@\n", currentLine];
    }
    NSLog(@"Result String: \n%@", resultString);