如何检查NSString格式是否包含与可变参数相同数量的说明符?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何检查NSString格式是否包含与可变参数相同数量的说明符?相关的知识,希望对你有一定的参考价值。
为了确保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"]
会记录
“两件事:你好和世界”
...但是[self thingsForStuff:CustomStuffTwo, @"Hello"]
会记录
“两件事:你好,”
......在它发生之前最好被抓住的东西。
有没有办法计算字符串中的格式说明符,最好是轻量级/便宜的?
有没有办法计算字符串中的格式说明符,最好是轻量级/便宜的?
不 - 真的不是。至少,如果您希望它跨所有可能的格式字符串工作,那就不是了。您必须复制stringWithFormat:
使用的解析器。即不要试图验证一切。
你可以计算%
的数量,但这不会像%%
或其他特殊情况那样。这可能足以满足您的目的。
好吧,我创建了自己的正则表达式,我不知道它是否会捕获所有这些,并可能最终找到一些误报,但似乎对我有用:
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)];
由于C和Objective-C处理类似你的可变函数/方法的方式,通常不能告诉用户提供了多少个参数。
以下是处理您情况的两种方法。
首先,寻找另一种方法来做到这一点。传递给方法的参数数量在编译时确定。所以也许你应该只使用三种方法而不是使用可变方法:
- (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
。您可以通过声明方法(在您的@interface
中)告诉编译器参数列表必须是nil终止的,如下所示:
@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);
}
long specifierCount = [myFormatString componentsSeparatedByString:@“%”]。count;
这会让你接近。它只是一个简单的分裂。您必须考虑转义的%值。
您可以计算格式说明符的数量,但是IIRC您永远无法计算传递给变量参数方法的参数数量。这是因为C推送堆栈上的参数而不指定推送的数量。
大多数函数通过要求最后一个参数为nil或某种终结符来克服这个问题(参见[NSArray arrayWithObjects:])。甚至还有一个宏允许编译器检查它并在编译时发出警告。
您可以在函数原型的末尾使用NS_FORMAT_FUNCTION
,如stringWithFormat
的NSString
方法。
所以你的方法的原型应该是这样的:
- (void)thingsForStuff:(CustomStuff)stuff, ... NS_FORMAT_FUNCTION(1,2);
以上是关于如何检查NSString格式是否包含与可变参数相同数量的说明符?的主要内容,如果未能解决你的问题,请参考以下文章
Obj-c - 如何检查 NSString 是不是包含一个或另一个?
如何检查 NS String 是不是包含 javascript 函数?