4

によって返されるフォーマットされた文字列NSString initWithFormat:arguments:が期待どおりであることを確認するには、引数と同じ数のフォーマット指定子があるかどうかを判断する必要があります。以下は(少し工夫され、高度に編集された)例です:

- (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);
}

このメソッドを使用すると、[self thingsForStuff:CustomStuffTwo, @"Hello", @"World"]ログに記録されます

「2つのこと:こんにちはと世界」

...しかし[self thingsForStuff:CustomStuffTwo, @"Hello"]ログに記録します

「2つのこと:こんにちはと」

...それが起こる前に捕まえられることが好ましい何か。

文字列内のフォーマット指定子、できれば軽量/安価なものを数える方法はありますか?

4

6 に答える 6

5

さて、私は自分の正規表現を作成しました。それがそれらすべてをキャッチするかどうかはわかりません。誤検知を見つけるのをやめるかもしれませんが、私のために働いているようです。

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

以下を使用して、引数の数を数えることができます。

NSRegularExpression *regEx = [NSRegularExpression regularExpressionWithPattern: kStringFormatSpecifiers options:0 error:nil];
NSInteger numSpecifiers = [regEx numberOfMatchesInString: yourString options:0 range:NSMakeRange(0, yourString.length)];
于 2015-04-13T08:16:41.420 に答える
2

CとObjective-Cがあなたのような可変個引数関数/メソッドを処理する方法のために、一般に、ユーザーが提供した引数の数を知ることはできません。

これがあなたの状況を処理する2つの方法です。

まず、これを行う別の方法を探します。メソッドに渡す引数の数は、コンパイル時に決定されます。したがって、可変個引数メソッドを使用する代わりに、次の3つのメソッドを使用する必要があります。

- (void)doStuff:(CustomStuff)stuff withThing:(Thing *)thing;
- (void)doStuff:(CustomStuff)stuff withThing:(Thing *)thing1 thing:(Thing *)thing2;
- (void)doStuff:(CustomStuff)stuff withThing:(Thing *)thing1 thing:(Thing *)thing2 hatWearer:(Cat *)cat;

また、渡す引数の数に基づいてコンパイル時に呼び出す適切なメソッドを選択し、switchステートメントを完全に排除します。

次に、事前定義されたフォーマット文字列は%@フォーマットのみを使用していることがわかります。(CustomStuff)stuffこれは、ユーザーが(引数を除いて)オブジェクトのみをメソッドに渡すことを期待していることを意味しますか?

ユーザーがオブジェクトのみをメソッドに渡し、それらの引数をnil以外にする必要がある場合は、コンパイラー支援を求めることができます。nil引数リストの最後でユーザーが渡すように要求するようにメソッドを変更します。@interface次のようにメソッドを(で)宣言することにより、引数リストをゼロで終了する必要があることをコンパイラーに伝えることができます。

@interface MyObject : NSObject

- (void)thingsForStuff:(CustomStuff)stuff, ... NS_REQUIRES_NIL_TERMINATION

@end

これで、コンパイラは、引数リストの最後にリテラルnilを付けずにメソッドを呼び出すと、ユーザーに「メソッドディスパッチにセンチネルがありません」と警告します。

したがって、APIを変更して、nil以外の引数の後にnil引数を要求するようにした後、次のようにnil以外の引数をカウントするようにメソッドを変更できます。

- (void)thingsForStuff:(CustomStuff)stuff, ... {
    int argCount = 0;
    va_list args;
    va_start(args, stuff);
    while (va_arg(args, id)) {
        ++argCount;
    }
    va_end(args)

    int expectedArgCount;
    NSString *format;
    switch (stuff) {
        case CustomStuffTwo:
            expectedArgCount = 2;
            format = @"Two things: %@ and %@";
            break;

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

        // etc.
    }

    NSAssert(argCount == expectedArgCount, @"%@ %s called with %d non-nil arguments, but I expected %d", self, (char*)_cmd, argCount, expectedArgCount);

    va_start(args, stuff);
    NSString *formattedStuff = [[NSString alloc] initWithFormat:format arguments:args];
    va_end(args);

    NSLog(@"Things: %@", formattedString);
}
于 2012-08-09T03:20:20.813 に答える
2

文字列内のフォーマット指定子、できれば軽量/安価なものを数える方法はありますか?

いいえ、そうではありません。少なくとも、考えられるすべてのフォーマット文字列で機能させたい場合はそうではありません。で使用されるパーサーを複製する必要がありますstringWithFormat:。つまり、すべてを検証しようとしないでください。

の数を数えることはできますが、それは他の特別な場合の%ようなものを捕らえることはできません。%%それはあなたの目的には十分かもしれません。

于 2012-08-09T01:03:36.783 に答える
0

フォーマット指定子の数を数えることはできますが、IIRCでは、可変引数メソッドに渡される引数の数を数えることはできません。これは、Cがプッシュした数を指定せずにスタックに引数をプッシュする方法が原因です。

ほとんどの関数は、最後の引数がnilまたはある種のターミネータであることを要求することによってこれを克服します([NSArray arrayWithObjects:]を参照)。コンパイラがこれをチェックし、コンパイル時に警告を発することを可能にするマクロさえあります。

于 2012-08-09T02:42:21.167 に答える
0

のメソッドのNS_FORMAT_FUNCTIONように、関数プロトタイプの最後で使用できます。stringWithFormatNSString

したがって、メソッドのプロトタイプは次のようになります。

- (void)thingsForStuff:(CustomStuff)stuff, ... NS_FORMAT_FUNCTION(1,2);
于 2016-07-04T14:46:35.697 に答える
-1

long specifierCount = [myFormatString componentsSeparatedByString:@ "%"]。count;

これはあなたを近づけるでしょう。その単純な分割。エスケープされた%値を考慮する必要があります。

于 2012-08-09T01:03:29.257 に答える