Objective-C String Formatting

By Josh Wright on December 2010 in tips

 

String formatting isn't especially a strength in Objective-C. Actually, it's just plain bare bones and reminds me a lot of C# formatting. Here's an example:

NSString* result = [NSString stringWithFormat:@"Hi %@, you are %i!", user.name, user.age];

//result == "Hi Josh, you are 28!";

This makes it difficult to deal with a bunch of variables. What if you want to add one, remove one, move it?

It also forces you to deal with types in your format string which I find annoying. To top it off, it's difficult to read.

So, of course, I decided to roll my own string formatting and what better to copy than the best language ever at string manipulation? Nope... not Perl. I'm talking about Ruby. Here's how you use it:

NSString* result = [@"Hi #{name}, you are #{age}!" format:user];

//result == "Hi Josh, you are 28!";

Just create a ruby-like format string, pass the object who's properties should be injected. Maybe you'd use "self" if you're talking about properties of the current instance.

This is, of course, a very simplistic approach to string formatting. It doesn't handle sub-expressions, local variables, or type-specific formatting (like decimal places). When I need it, I'll probably add these features.

As always, if anybody knows of a library that already does this then PLEEEEEEASE let me know. I'm past the "roll your own" era of my life, but I do need the library.

You can find the code in the BendyTree iOS library on GitHub. It's in the "StringFormatting" folder. I ended up pulling this from the lib for now, see the original code below:

import "RegexKitLite.h"

  • (NSString) formatString:(NSString)str withObject:(id)obj

{

NSArray* matches = [str arrayOfCaptureComponentsMatchedByRegex:@"#\\{[^}]*\\}"];



for(NSArray* match in matches){

    NSString* matchStr = [match objectAtIndex:0];

    NSString* key = [matchStr substringWithRange:NSMakeRange(2, [matchStr length]-3)];

    NSString* value = [[obj valueForKey:key] description];

    str = [str stringByReplacingOccurrencesOfString:matchStr withString:value];

}



return str;

}