views:

513

answers:

3

Greetings,

I am new to objective c, and I have the following issue:

I have a NSString:

 "There are seven words in this phrase"

I want to divide this into 3 smaller strings (and each smaller string can be no longer than 12 characters in length) but must contain whole words separated by a space, so that I end up with:

String1 = "There are" //(length is 9 including space)
String2 = "seven words"// (length is 11)
String3 = "in this" //(length is 7), with the word "phrase" ignored as this would exceed the maximum length of 12..

Currently I am splitting my original array into an array with:

NSArray *piecesOfOriginalString = [originalString componentsSeparatedByString:@" "];

Then I have multiple "if" statements to sort out situations where there are 3 words, but I want to make this more extensible for any array up to 39 (13 characters * 3 line) letters, with any characters >40 being ignored. Is there an easy way to divide a string based on words or "phrases" up to a certain length (in this case, 12)?

+2  A: 

well, you can keep splitting the string as you're already doing, or you could check out whether NSScanner suits your needs. In any case, you're going to have to do the math yourself.

NSResponder
A: 

Something similar to this? (Dry-code warning)

NSArray *piecesOfOriginalString = [originalString componentsSeparatedByString:@" "];

NSMutableArray *phrases  = [NSMutableArray array];
NSString *chunk = nil;
NSString *lastchunk = nil;

int i, count = [piecesOfOriginalString count];
for (i = 0; i < count; i++) {
    lastchunk = [[chunk copy] autorelease];

    if (chunk) {
        chunk = [chunk stringByAppendingString:[NSString stringWithFormat:@" %@", [piecesOfOriginalString objectAtIndex:i]]];
    } else {
        chunk = [[[piecesOfOriginalString objectAtIndex:i] copy] autorelease];
    }

    if ([chunk length] > 12) {
        [phrases addObject:lastchunk];
        chunk = nil;
    }

    if ([phrases count] == 3) {
        break;
    }
}
Bryan McLemore
A: 

Thanks McLemore, that is really helpful! I will try this immediately. My current solution is very similar, but less refined, as I hard coded the loops and use individual variable to hold the sub strings (called them TopRow, MidRow, and BottomRow), that and the memory management issue is overlooked... :

int maxLength = 12; // max chars per line (in each string)
int j=0; // for looping, j is the counter for managing the words in the "for" loop
TopRow = nil; //1st string
MidRow = nil; //2nd string
//BottomRow = nil; //third row string (not implemented yet)
BOOL Row01done = NO; // if YES, then stop trying to fill row 1
BOOL Row02done = NO; // if YES, then stop trying to fill row 2
largeArray = @"Larger string with multiple words";

tempArray = [largeArray componentsSeparatedByString:@" "];
for (j=0; j<[tempArray count]; j=j+1) {
    if (TopRow == nil) {
     TopRow = [tempArray objectAtIndex:j];
    }
    else {
     if (Row01done == YES) {
      if (MidRow == nil) {
       MidRow = [tempArray objectAtIndex:j];
      }
      else {
       if (Row02done == YES) {
        //row 3 stuff goes here... unless I can rewrite as iterative loop...
        //will need to uncommend BottomRow = nil; above..
       }       
       else {
        if ([MidRow length] + [[tempArray objectAtIndex:j] length] < maxLength) {
         MidRow = [MidRow stringByAppendingString:@" "];
         MidRow = [MidRow stringByAppendingString:[tempArray objectAtIndex:j]];
        }
        else {
         Row02done = YES;
         //j=j-1; // uncomment once BottowRow loop is implemented
        }
       }
      }
     }
     else {
      if (([TopRow length] + [[tempArray objectAtIndex:j] length]) < maxLength) {
       TopRow = [TopRow stringByAppendingString:@" "];
       TopRow = [TopRow stringByAppendingString:[tempArray objectAtIndex:j]];
      }
      else {
       Row01done = YES;
       j=j-1; //end of loop without adding the string to TopRow, subtract 1 from j and start over inside Mid Row
      }
     }   
    }
}
J. Dave
Ya, that's a little nasty, I do what I can to keep my code shallow, it keeps things much more readable and maintainable.
Bryan McLemore