Search code examples
objective-cnsstringstringwithformatvariadic-functions

How to check if NSString format contains the same number of specifiers as there are variadic arguments?


To ensure that a formatted string returned by NSString initWithFormat:arguments: is as expected, I need to determine if there are the same number of format specifiers as arguments. Below is a (slightly contrived and highly edited) example:

- (void)thingsForStuff:(CustomStuff)stuff, ...
{
    NSString *format;
    switch (stuff)
    {
        case CustomStuffTwo:
            format = @"Two things: %@ and %@";
        break;

        case CustomStuffThree:
            format = @"Three things: %@, %@, and %@";
        break;

        default:
            format = @"Just one thing: %@";
        break;
    }

    va_list args;
    va_start(args, method);
    // Want to check if format has the same number of %@s as there are args, but not sure how
    NSString *formattedStuff = [[NSString alloc] initWithFormat:format arguments:args];
    va_end(args);

    NSLog(@"Things: %@", formattedStuff);
}

Using this method, [self thingsForStuff:CustomStuffTwo, @"Hello", @"World"] would log

"Two things: Hello and World"

...but [self thingsForStuff:CustomStuffTwo, @"Hello"] would log

"Two things: Hello and "

...something that would be preferred to be caught before it happens.

Is there a way to count the format specifiers in a string, preferably something lightweight/inexpensive?


Solution

  • Is there a way to count the format specifiers in a string, preferably something lightweight/inexpensive?

    Nope -- really isn't. At least, not if you want it to work across all possible format strings. You would have to duplicate the parser that is used by stringWithFormat:. I.e. don't try to validate everything.

    You could count the number of %, but that would not catch things like %% or other special cases. That may be good enough for your purposes.