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:]
).