Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 292
Metric Scantlings Avatar asked Feb 20 '23 14:02

Metric Scantlings


2 Answers

Well, I created my own regex, I have no idea if it's going to catch all of them, and may end finding some false positives, but seems to be working for me:

static NSString *const kStringFormatSpecifiers =
@"%(?:\\d+\\$)?[+-]?(?:[lh]{0,2})(?:[qLztj])?(?:[ 0]|'.{1})?\\d*(?:\\.\\d+)?[@dDiuUxXoOfeEgGcCsSpaAFn]";

You can count the number of arguments using:

NSRegularExpression *regEx = [NSRegularExpression regularExpressionWithPattern: kStringFormatSpecifiers options:0 error:nil];
NSInteger numSpecifiers = [regEx numberOfMatchesInString: yourString options:0 range:NSMakeRange(0, yourString.length)];
like image 100
3 revs, 3 users 41% Avatar answered Feb 22 '23 03:02

3 revs, 3 users 41%


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.

like image 36
bbum Avatar answered Feb 22 '23 03:02

bbum