Это должно быть легко, но мне сложно найти самое простое решение.
Мне нужен NSString, который равен другой строке, сцепленной с собой определенное количество раз.
Для лучшего объяснения рассмотрим следующий пример Python:
>> original = "abc"
"abc"
>> times = 2
2
>> result = original * times
"abcabc"
Какие-нибудь намеки?
Обновлено:
Я собирался опубликовать решение, подобное решению Ответ Майка Макмастера, после просмотра этой реализации из OmniFrameworks:
// returns a string consisting of 'aLenght' spaces
+ (NSString *)spacesOfLength:(unsigned int)aLength;
{
static NSMutableString *spaces = nil;
static NSLock *spacesLock;
static unsigned int spacesLength;
if (!spaces) {
spaces = [@" " mutableCopy];
spacesLength = [spaces length];
spacesLock = [[NSLock alloc] init];
}
if (spacesLength < aLength) {
[spacesLock lock];
while (spacesLength < aLength) {
[spaces appendString:spaces];
spacesLength += spacesLength;
}
[spacesLock unlock];
}
return [spaces substringToIndex:aLength];
}
Код воспроизведен из файла:
Frameworks/OmniFoundation/OpenStepExtensions.subproj/NSString-OFExtensions.m
на платформе OpenExtensions из Omni Frameworks от Группа Омни.





NSString *original = @"abc";
int times = 2;
// Capacity does not limit the length, it's just an initial capacity
NSMutableString *result = [NSMutableString stringWithCapacity:[original length] * times];
int i;
for (i = 0; i < times; i++)
[result appendString:original];
NSLog(@"result: %@", result); // prints "abcabc"
Я сделал его немного более эффективным с момента принятия, указав сначала время и указав емкость = [исходная длина] * раз
Для полноты картины, если по какой-то причине вы хотите использовать большие числа, вы можете улучшить это, повторно используя конкатенации степени двойки (например, foo * 10 = foo * 2 + foo * 8; foo * 8 = foo * 4 + foo * 4; foo * 4 = foo * 2 + foo * 2 -> 3 операции concat вместо 9).
Это решение не так эффективно, как верхний ответ с использованием stringByPaddingToLength:withString:startingAtIndex:
Если вы используете Cocoa в Python, вы можете просто сделать это, поскольку PyObjC наделяет NSString всеми возможностями класса Python unicode.
В противном случае есть два пути.
Один из них - создать массив с одинаковой строкой в нем n раз и использовать componentsJoinedByString:. Что-то вроде этого:
NSMutableArray *repetitions = [NSMutableArray arrayWithCapacity:n];
for (NSUInteger i = 0UL; i < n; ++i)
[repetitions addObject:inputString];
outputString = [repetitions componentsJoinedByString:@""];
Другой способ - начать с пустого NSMutableString и добавить к нему строку n раз, например:
NSMutableString *temp = [NSMutableString stringWithCapacity:[inputString length] * n];
for (NSUInteger i = 0UL; i < n; ++i)
[temp appendString:inputString];
outputString = [NSString stringWithString:temp];
Вы можете отключить вызов stringWithString:, если вы можете вернуть здесь изменяемую строку. В противном случае вам, вероятно, следует вернуть неизменяемую строку, а сообщение stringWithString: здесь означает, что у вас есть две копии строки в памяти.
Поэтому рекомендую решение componentsJoinedByString:.
[Edit: Заимствованная идея использовать методы …WithCapacity: из Ответ Майка Макмастера.]
Спасибо за альтернативу использованию componentsJoinedByString.
Да, хорошее предложение. Вероятно, немного более эффективно, чем мое (по общему признанию общее) решение.
Для повышения производительности вы можете перейти на C примерно так:
+ (NSString*)stringWithRepeatCharacter:(char)character times:(unsigned int)repetitions;
{
char repeatString[repetitions + 1];
memset(repeatString, character, repetitions);
// Set terminating null
repeatString[repetitions] = 0;
return [NSString stringWithCString:repeatString];
}
Это можно было бы записать как расширение категории в классе NSString. Вероятно, есть несколько проверок, которые следует добавить туда, но это прямая суть.
Отличная идея, особенно для сценариев, требующих высокой производительности. Спасибо!
Дэвид, повторения - это беззнаковое целое число
Я не удивлюсь, если окажется, что NSStringstringByPaddingToLength:withString:startingAtIndex: реализован таким же образом.
Первый способ, описанный выше, предназначен для одного символа. Это для строки символов. Его также можно использовать для одиночного символа, но он требует больше накладных расходов.
+ (NSString*)stringWithRepeatString:(char*)characters times:(unsigned int)repetitions;
{
unsigned int stringLength = strlen(characters);
unsigned int repeatStringLength = stringLength * repetitions + 1;
char repeatString[repeatStringLength];
for (unsigned int i = 0; i < repetitions; i++) {
unsigned int pointerPosition = i * repetitions;
memcpy(repeatString + pointerPosition, characters, stringLength);
}
// Set terminating null
repeatString[repeatStringLength - 1] = 0;
return [NSString stringWithCString:repeatString];
}
Я думаю, что есть ошибка внутри цикла for: unsigned int pointerPosition = i * repetitions; должен быть unsigned int pointerPosition = i * stringLength;, где я * повторения становится я * stringLength.
Есть метод под названием stringByPaddingToLength:withString:startingAtIndex::
[@"" stringByPaddingToLength:100 withString: @"abc" startingAtIndex:0]
Обратите внимание, что если вам нужно 3 abc, используйте 9 (3 * [@"abc" length]) или создайте категорию, подобную этой:
@interface NSString (Repeat)
- (NSString *)repeatTimes:(NSUInteger)times;
@end
@implementation NSString (Repeat)
- (NSString *)repeatTimes:(NSUInteger)times {
return [@"" stringByPaddingToLength:times * [self length] withString:self startingAtIndex:0];
}
@end
+1 за то, что все это делается за один вызов стандартной библиотеки. И вот как я использовал его для создания списка вопросительных знаков, разделенных запятыми (для передачи в SQLite) - [@"" stringByPaddingToLength:[fields count]*2-1 withString:@"?," startingAtIndex:0].
Я пытался придумать что-то попроще, но думаю, что это самый короткий путь.