2008-11-04 10 views
51

To powinno być łatwe, ale ciężko jest mi znaleźć najłatwiejsze rozwiązanie.Utwórz NSString, powtarzając kolejny ciąg z określoną liczbą razy

Potrzebuję NSString, który jest równy innemu ciągowi połączonemu ze sobą określoną liczbę razy.

Dla lepszego wyjaśnienia, rozważmy następujący przykład Pythona:

>> original = "abc" 
"abc" 
>> times = 2 
2 
>> result = original * times 
"abcabc" 

Wszelkie wskazówki?


EDIT:

miałem zamiar pisać rozwiązanie podobne do tego, by Mike McMaster's answer, po obejrzeniu tego wdrożenia od 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]; 
} 

Kod odtworzonego z pliku:

Frameworks/OmniFoundation/OpenStepExtensions.subproj/NSString-OFExtensions.m 

w środowisku OpenExtensions z Omni Frameworks przez The Omni Group.

Odpowiedz

145

Jest to metoda zwana stringByPaddingToLength:withString:startingAtIndex::

[@"" stringByPaddingToLength:100 withString: @"abc" startingAtIndex:0] 

Pamiętaj, że jeśli chcesz 3 abc, niż korzystać z 9 (3 * [@"abc" length]) lub stworzyć własną kategorię tak:

@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 
+3

+1 za zrobienie tego wszystkiego w jednym wywołaniu do standardowej biblioteki. A oto, jak go użyłem, aby utworzyć listę znaków zapytania oddzielonych przecinkami (do karmienia SQLite) - "[@" "stringByPaddingToLength: [pola count] * 2-1 withString: @" ?, "startingAtIndex: 0] '. – noamtm

7
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" 
+0

Starałam wymyślić coś prostszego, ale myślę, że to najkrótsza droga. –

+0

Zrobiłem to trochę bardziej wydajnie od czasu akceptacji, określając czasy jako pierwsze i mając pojemność = [oryginalna długość] * razy –

+1

Tylko dla kompletności, jeśli z jakiegoś powodu chcesz używać dużych liczb, możesz to poprawić przez ponowne użycie mocy. z dwóch konkatenacji (np. foo * 10 = foo * 2 + foo * 8; foo * 8 = foo * 4 + foo * 4; foo * 4 = foo * 2 + foo * 2 -> 3 operacje concat zamiast 9) . –

1

Jeśli używasz kakao w Pythonie, a następnie można po prostu zrobić, że jak imbues PyObjC NSString ze wszystkich możliwości klasy w Pythonie unicode.

W przeciwnym razie istnieją dwa sposoby.

Jedną z nich jest utworzenie tablicy z tym samym ciągiem w niej n razy i użycie componentsJoinedByString:. Coś takiego:

NSMutableArray *repetitions = [NSMutableArray arrayWithCapacity:n]; 
for (NSUInteger i = 0UL; i < n; ++i) 
    [repetitions addObject:inputString]; 
outputString = [repetitions componentsJoinedByString:@""]; 

Innym sposobem byłoby zacząć z pustym NSMutableString i dołączania ciąg do niego n razy, tak:

NSMutableString *temp = [NSMutableString stringWithCapacity:[inputString length] * n]; 
for (NSUInteger i = 0UL; i < n; ++i) 
    [temp appendString:inputString]; 
outputString = [NSString stringWithString:temp]; 

Możesz być w stanie wyciąć stringWithString: zadzwoń, jeśli możesz tu zwrócić zmienny łańcuch. W przeciwnym razie prawdopodobnie powinieneś zwrócić niezmienny ciąg znaków, a komunikat stringWithString: oznacza, że ​​masz dwie kopie ciągu w pamięci.

Dlatego polecam rozwiązanie componentsJoinedByString:.

[Edit: Borrowed pomysł na wykorzystanie …WithCapacity: metod z Mike McMaster's answer.]

+0

Dzięki za alternatywę użycia componentsJoinedByString. –

+0

Tak, dobra sugestia. Prawdopodobnie trochę bardziej wydajne niż moje (wprawdzie ogólne) rozwiązanie. –

4

na wydajność, można wpaść C z mniej więcej tak:

+ (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]; 
} 

To może być napisany jako rozszerzenie kategorii na klasa NSString. Prawdopodobnie są tam jakieś kontrole, ale jest to prosty punkt wyjścia.

+0

Świetny pomysł, szczególnie dla scenariuszy głodnych wydajności. Dzięki! –

+0

sprawdź czy powtórzenia> 0? –

+0

David, powtórzenia to niepodpisane int – jessecurry

2

Pierwsza metoda powyżej dotyczy pojedynczego znaku. Ta jest dla ciągu znaków. Może być również używany do pojedynczego znaku, ale ma więcej narzutów.

+ (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]; 
} 
+0

Wystąpił błąd, myślę, wewnątrz do cyklu: 'unsigned int pointerPosition = i * powtórzeń;' powinny być 'unsigned int pointerPosition = i * stringLength;' gdzie ** i * powtórzeń ** staje ** i * stringLength **. – mginius

Powiązane problemy