2009-06-30 1 views
71

C 번호는 문자열 형식 지정자에 인수 인덱스를 지정할 수 있습니다 구문, 예컨대 :NSString stringWithFormat에서 인수 위치/인덱스를 지정하는 방법이 있습니까?

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

당신은 인수 번 이상을 사용하고 또한 사용에서 제공되는 인수를 생략 할 수있다. Another question%[index]$[format]의 형식으로 C/C++에 대해 동일한 서식을 언급합니다. %1$i. NSString을 으로 완전히 가져올 수 없었습니다. 형식에서을 생략하면 이 잘 동작하므로이 구문을 완전히 준수해야합니다.은이 구문을 존중합니다. 예상대로 작동하지 않습니다 다음 (EXC_BAD_ACCESS IT는 NSObject의 *로 age 매개 변수를 역 참조에 시도하기 때문에) :

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

위치 적 인수

가 될 것으로 보인다 형식 (에서 누락 된 인수가없는 경우에만 존중 이상한 요구 사항) :

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

은 이러한 모든 호출이 OS X에서 제대로 작동 :

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

는 accomplishin의 방법이있다 g Objective-C/Cocoa의 NSString을 사용합니까? 지역화를 위해 유용 할 것입니다.

+0

버그 신고서를 제출하고 버그 번호를 알려주십시오. –

답변

110

NSString 및 CFString은 재정렬 가능/위치 지정 인수를 지원합니다. 또한

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

, 다음 코드는이 문제에 지정된 버그를 해결 Apple: String Resources

+3

몇 가지 설명으로 질문을 업데이트했습니다. 그것은 코코아가 형식에서 생략 된 인수를 존중하지 않는 것으로 나타났습니다. 이는 형식 위반의 부작용이었습니다. – Jason

+2

C에서 varargs가 작동하기 때문에 생략 된 인수를 존중할 수 없습니다. 인수의 수 또는 크기를 알 수있는 표준 방법이 없습니다. 문자열 구문 분석은 형식 지정자에서 정보를 추론하여 처리하며 지정자가 실제로 필요합니다. –

+1

va_args의 작동 방식을 이해합니다. 그러나 예상대로 작동하는 것으로 보입니다. printf ("Age : % 2 $ i", [name UTF8String], age); 재정렬 된/누락 된 args있는 다른 printf 시도했다 및 NSString 않는 반면 그들은 모두 예상 된 출력 줄. – Jason

0

더 많은 연구를 한 후, 코코아는 위치 구문을 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에서 구현 된 것이 있으면 좋을 것입니다.

+1

'sprintf'는 Cocoa의 일부가 아니며 C 표준 라이브러리의 일부이며 구현은'stringWithFormat :'/'initWithFormat :'입니다. –

+0

내 이전 설명을 분명히하기 : 코코아 버전은'stringWithFormat :'/'initWithFormat :'입니다. 이것은'sprintf'와 친구들의 구현 (현재는'CFStringCreateWithFormat')입니다. –

+4

정확히 512 바이트의 msg를 초기화하는 것은 무작위 객체에서 무작위 선택기를 수행하는 것만큼이나 안전하다는 사실을 언급하는 데 거의 사용되지 않는다고 생각합니다. 알지 못하는 사람들에게 : 고정 크기 버퍼는 해고하는 가장 쉬운 방법 중 일부입니다. google : buffer overflow –

1

의 설명서를 참조하십시오. 이 문제를 해결하고 자리 표시 자의 번호를 채워서 간격을 메우십시오.

+ (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; 
} 
관련 문제