views:

327

answers:

3

Given the following sequence:

"normal %(b)BOLD% normal"

I want to transform this into the following string:

"0000000%(b)bbbb%0000000"

In other words, '%(b)' specifies that all characters up until the next '%' should be 'b'. All other characters should be '0'.

I have tried numerous approaches, including using the RegexKitLite regular expression library but cannot seem to get my head around it.

Can anyone give me some pointers?

+1  A: 

You can use the NSScanner to scan the source string and locate the place holders ('%(b)' and '%') ... then use the locations (I mean to the filed 'location' of a NSRange struct) to modify the source string as you want!

P.S: I'm sorry for my english! :-(

BitDrink
Don't worry, your english is fine. Thanks
Xetius
+1  A: 

Yeah, using regexes was my gut reaction too, but with your requirements, it'd probably be simpler just to scan the string. Since you're dealing with individual characters, this will also be easiest to do in C. So here are a couple pointers:

const char * original = [@"normal %(b)BOLD% normal" UTF8String];
char * mutable = malloc((strlen(original)+1) * sizeof(char));
//we have to make a copy of the characters because we can't modify an NSString directly
strcpy(mutable, original);

//just a couple flags
char * pointer = mutable;
int isInBoldBlock = 0;
//loop until the end of the string
while (*pointer != '\0') {
  if (isInBoldBlock) {
    if (*pointer != '%') {
      //we're in a bold block and found a char that isn't %
      *pointer = 'b';
    } else {
      //we found the end of the bold block
      isInBoldBlock = 0;
    }
  } else {
    //look to see if we're going to start a bold section
    if (*pointer == '%' && *(pointer+1) == '(' && *(pointer+2) == 'b' && *(pointer+3) == ')') {
      isInBoldBlock = 1;
      pointer += 3; //skip the %(b) characters
    } else {
      //we're not in a bold block, and we're not about to start one:
      *pointer = '0';
    }
  }
  //move to the next character
  pointer++;
}

//this will create a copy of "mutable"
NSString * final = [[NSString alloc] initWithUTF8String:mutable];
//free the memory we allocated
free(mutable);
NSLog(@"Final: %@", final);
//release the constructed string
[final release];

There might be a more "Cocoa" way to do this, particularly with NSScanner, but I am unfamiliar with this class, and the above method works.

CAVEAT IMPLEMENTOR: the "%(b)" and closing "%" bits MUST be the ASCII characters. This will behave strangely if you have beyond-ascii characters in the string. Consider transforming the string to ASCII before using this (with -[NSString dataUsingEncoding:allowLossyConversion:]).

Dave DeLong
I had kind of come to this conclusion myself, and had given up on regex for now.
Xetius
A: 

Doesn't look to me like NSScanner is called for here. See -rangeOfString: and -rangeOfString:options: in the NSString documentation.

NSResponder
NSString (and NSScanner) are certainly convenient for finding strings, but when it comes to replacing them, only NSMutableString would have that capability, and even there you'd have to do work arounds to make sure you're replacing the correct number of characters.
Dave DeLong