Есть ли способ указать позицию / индекс аргумента в NSString stringWithFormat?
C # имеет синтаксис, который позволяет указать индекс аргумента в спецификаторе формата строки, например:
string message = string.Format("Hello, {0}. You are {1} years old. How does it feel to be {1}?", name, age);
Вы можете использовать аргументы более одного раза и также опускать аргументы, которые предоставляются от использования. В другом вопросе упоминается одно и то же форматирование для C / C ++ в виде %[index]$[format]
, например %1$i
. Я не смог заставить NSString полностью соблюдать этот синтаксис, потому что он хорошо себя ведет, когда опускает аргументы из формата. Следующее не работает должным образом (EXC_BAD_ACCESS, поскольку он пытается разыменовать age
параметр как NSObject *):
int age = 23; NSString * name = @"Joe"; NSString * message = [NSString stringWithFormat:@"Age: %2$i", name, age];
Позиционные аргументы соблюдаются только в том случае, если отсутствуют отсутствующие аргументы из формата (что представляется нечетным требованием):
- XCode 4 зависает при «Присоединении к (имя приложения)»
- Почему вы используете символ подчеркивания для переменной экземпляра, но не соответствующее ему свойство?
- Лучшая производительность с помощью libxml2 или NSXMLParser на iPhone?
- NSDateFormatter dateFromString возвращает nil
- NSArray слабых ссылок (__unsafe_unretained) для объектов под ARC
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);
Есть ли способ выполнить это, используя NSString в Objective-C / Cocoa? Это было бы полезно для целей локализации.
- Как добавить UIView над текущим UITableViewController
- запись NSDictionary для plist в моем приложении
- Анимированный gif не работает в наложении MKMapView с использованием MKOverlayRenderer
- Переменные экземпляра для объектов Objective C
- Как отсортировать NSMutableArray с помощью sortedArrayUsingDescriptors?
- Лучшая библиотека Cocoa / Objective-C Wrapper для SQLite на iPhone
- Позиционирование MKMapView для одновременного отображения нескольких аннотаций
- UITextView внутри UIScrollView с AutoLayout
NSString и CFString поддерживают переопределяемые / позиционные аргументы.
NSString *string = [NSString stringWithFormat: @"Second arg: %[email protected], First arg %[email protected]", @"<1111>", @"<22222>"]; NSLog(@"String = %@", string);
Также см. Документацию в Apple: String Resources
Следующий код исправляет ошибку, указанную в этой проблеме. Это временное решение и позволяет заполнителям заполнить пробелы.
+ (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; }
После проведения большего количества исследований кажется, что 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.