是否有方法在 NSString stringWithFormat 中指定参数位置/索引?

C # 的语法允许您在字符串格式说明符中指定参数索引,例如:

string message = string.Format("Hello, {0}. You are {1} years old. How does it feel to be {1}?", name, age);

可以多次使用参数,也可以省略在使用时提供的参数。另一个问题%[index]$[format]的形式提到了 C/C + + 的相同格式,例如 %1$i。我还没有能够让 NSString 到 完全尊重这种语法,因为它确实表现良好时,从 省略论点的格式。下面的代码不能正常工作(EXC _ BAD _ ACCESS,因为它试图将 age参数解引用为 NSObject *) :

int age = 23;
NSString * name = @"Joe";
NSString * message = [NSString stringWithFormat:@"Age: %2$i", name, age];

位置参数只有在格式中没有丢失参数(这似乎是一个奇怪的要求)时才受到尊重:

NSString * message = [NSString stringWithFormat:@"Age: %2$i; Name: %1$@", name, age];

所有这些调用在 OS X 中都能正常工作:

printf("Age: %2$i", [name UTF8String], age);
printf("Age: %2$i %1$s", [name UTF8String], age);

在 Objective-C/Cocoa 中有没有使用 NSString 来实现这一点的方法。

19639 次浏览

经过更多的研究,似乎 Cocoa 尊重 printf中的位置语法:

char msg[512] = {0};
NSString * format = @"Age %2$i, Name: %1$s"; // loaded from resource in practice
sprintf(msg, [format UTF8String], [name UTF8String], age);
NSString * message = [NSString stringWithCString:msg encoding:NSUTF8StringEncoding];

但是,如果在 NSString 上有这样的实现就更好了。

NSString 和 CFString 支持可重排/位置参数。

NSString *string = [NSString stringWithFormat: @"Second arg: %2$@, First arg %1$@", @"<1111>", @"<22222>"];
NSLog(@"String = %@", string);

另外,请参阅 苹果: 字符串资源上的文档

下面的代码修复了此问题中指定的 bug。这是一种变通方法,可以对占位符重新编号以填补空白。

+ (id)stringWithFormat:(NSString *)format arguments:(NSArray*) arguments
{
NSMutableArray *filteredArguments = [[NSMutableArray alloc] initWithCapacity:arguments.count];
NSMutableString *correctedFormat = [[NSMutableString alloc ] initWithString:format];
NSString *placeHolderFormat = @"%%%d$";


int actualPlaceholderIndex = 1;


for (int i = 1; i <= arguments.count; ++i) {
NSString *placeHolder = [[NSString alloc] initWithFormat:placeHolderFormat, i];
if ([format rangeOfString:placeHolder].location != NSNotFound) {
[filteredArguments addObject:[arguments objectAtIndex:i - 1]];


if (actualPlaceholderIndex != i) {
NSString *replacementPlaceHolder = [[NSString alloc] initWithFormat:placeHolderFormat, actualPlaceholderIndex];
[correctedFormat replaceAllOccurrencesOfString:placeHolder withString:replacementPlaceHolder];
[replacementPlaceHolder release];
}
actualPlaceholderIndex++;
}
[placeHolder release];
}


if (filteredArguments.count == 0) {
//No numbered arguments found: just copy the original arguments. Mixing of unnumbered and numbered arguments is not supported.
[filteredArguments setArray:arguments];
}


NSString* result;
if (filteredArguments.count == 0) {
//Still no arguments: don't use initWithFormat in this case because it will crash: just return the format string
result = [NSString stringWithString:format];
} else {
char *argList = (char *)malloc(sizeof(NSString *) * [filteredArguments count]);
[filteredArguments getObjects:(id *)argList];
result = [[[NSString alloc] initWithFormat:correctedFormat arguments:argList] autorelease];
free(argList);
}


[filteredArguments release];
[correctedFormat release];


return result;
}