Objective c 有没有办法在NSString stringWithFormat中指定参数位置/索引?

Objective c 有没有办法在NSString stringWithFormat中指定参数位置/索引?,objective-c,cocoa,Objective C,Cocoa,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完全遵守这种语法,因为它在从格式中省略参数时表现良好。以下操作未按预期工作

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*取消引用):

只有当格式中没有缺少参数时(这似乎是一个奇怪的要求),才会考虑位置参数:

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

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

在Objective-C/Cocoa中使用NSString是否有实现此目的的方法?这对于本地化很有用。

在做了更多的研究之后,似乎在
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);
NSString*string=[NSString stringWithFormat:@“第二个参数:%2$@,第一个参数%1$@,@”,“@]”;
NSLog(@“String=%@”,String);

另外,请参阅

上的文档,以下代码修复了本期中指定的错误。这是一种变通方法,可对占位符重新编号以填补空白

+ (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;
}
+(id)stringWithFormat:(NSString*)格式参数:(NSArray*)参数
{
NSMutableArray*filteredArguments=[[NSMutableArray alloc]initWithCapacity:arguments.count];
NSMutableString*correctedFormat=[[NSMutableString alloc]initWithString:format];
NSString*占位符格式=@“%%%d$”;
int actualPlaceholderIndex=1;

对于(int i=1;我已经用一些澄清更新了这个问题。Cocoa似乎不尊重格式中省略的参数,这是我收到的访问冲突的副作用。由于C中varargs的工作方式,不可能尊重省略的参数。没有标准的方法来知道参数的数量或它们的值ize.String解析通过从格式说明符推断信息来处理此问题,这要求说明符实际存在。我理解va_args的工作原理;但是,这似乎与预期的一样:printf(“年龄:%2$I”,[name UTF8String],年龄);我尝试过其他带有重新排序/缺少参数的printf,它们都给出了预期的输出,而NSString没有。只是重申我的发现:
stringWithFormat:
支持位置参数,只要所有参数都在格式字符串中指定。Se也
sprintf
不是cococa的一部分,它是C的一部分标准库,它的实现是
stringWithFormat:
/
initWithFormat:
。澄清我之前的评论:Cocoa版本是
stringWithFormat:
/
initWithFormat:
。它是一个单独的实现(目前,
CFStringCreateWithFormat
)从
sprintf
和朋友那里。我想没有必要评论这样一个事实,即用512字节初始化msg与在随机对象上执行随机选择器一样安全,但无论如何。对任何不知道的人来说:固定大小的缓冲区是一些最容易被触发的方法。google:buffer overflowFile错误报告(让我们知道错误)。
NSString *string = [NSString stringWithFormat: @"Second arg: %2$@, First arg %1$@", @"<1111>", @"<22222>"];
NSLog(@"String = %@", string);
+ (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;
}