2008-11-04 4 views
51

Cela devrait être facile, mais j'ai du mal à trouver la solution la plus simple.Créer NSString en répétant une autre chaîne un certain nombre de fois

J'ai besoin d'un NSString qui est égal à une autre chaîne concaténée avec elle-même un certain nombre de fois.

Pour une meilleure explication, considérons l'exemple python suivant:

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

Tous les conseils?


EDIT:

je vais poster une solution similaire à celle par Mike McMaster's answer, après avoir examiné cette mise en œuvre des 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]; 
} 

code reproduit à partir du fichier:

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

sur le framework OpenExtensions à partir du Omni Frameworks par The Omni Group.

Répondre

145

Il y a une méthode appelée stringByPaddingToLength:withString:startingAtIndex::

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

Notez que si vous voulez 3 abc, que d'utiliser 9 (3 * [@"abc" length]) ou créer la catégorie comme ceci:

@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 pour tout faire en un seul appel à la bibliothèque standard. Et voici comment je l'ai utilisé pour créer une liste de points d'interrogation séparés par des virgules (pour alimenter SQLite) - '[@" "stringByPaddingToLength: [fields count] * 2-1 avecString: @" ?, "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

Je tentais pour trouver quelque chose de plus simple, mais je pense que c'est le plus court chemin. –

+0

Je l'ai fait un peu plus efficace depuis l'acceptation en spécifiant les temps d'abord et ayant la capacité = [longueur d'origine] * fois –

+1

Juste pour être complet, si pour une raison quelconque vous voulez utiliser de grands nombres, vous pouvez améliorer cela en réutilisant de deux concaténations (par exemple foo * 10 = foo * 2 + foo * 8; foo * 8 = foo * 4 + foo * 4; foo * 4 = foo * 2 + foo * 2 -> 3 opérations de concaténation au lieu de 9) . –

1

Si vous utilisez Cocoa en Python, alors vous pouvez juste faire, comme PyObjC toutes NSString insuffle des capacités de la classe Python unicode.

Sinon, il y a deux façons.

On doit créer un tableau avec la même chaîne n fois, et utiliser componentsJoinedByString:. Quelque chose comme ceci:

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

L'autre façon serait de commencer par un vide NSMutableString et ajouter la chaîne à ce n fois, comme ceci:

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

Vous pourriez être en mesure de découper la stringWithString: appelez si cela vous convient pour renvoyer une chaîne mutable ici. Sinon, vous devriez probablement retourner une chaîne immuable, et le message stringWithString: signifie ici que vous avez deux copies de la chaîne en mémoire. Par conséquent, je recommande la componentsJoinedByString: solution.

[Edit: Emprunté idée d'utiliser …WithCapacity: méthodes de Mike McMaster's answer.]

+0

Merci pour l'alternative d'utiliser componentsJoinedByString. –

+0

Oui, bonne suggestion. Probablement un petit peu plus efficace que ma solution (certes générique). –

4

Pour les performances, vous pourriez tomber dans C avec quelque chose comme ceci:

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

Cela pourrait être écrit comme une extension de la catégorie sur la classe NSString. Il y a probablement des vérifications à y faire, mais c'est l'essentiel.

+0

Excellente idée, spécialement pour les scénarios de performance. Merci! –

+0

vérifier si les répétitions> 0? –

+0

David, répétitions est un entier non signé – jessecurry

2

La première méthode ci-dessus concerne un seul caractère. Celui-ci est pour une chaîne de caractères. Il pourrait aussi être utilisé pour un seul personnage mais a plus de frais généraux.

+ (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

Il y a une erreur, je pense, à l'intérieur du pour le cycle: 'unsigned int i = pointerPosition * répétitions,' devrait être 'unsigned int i = pointerPosition * StringLength,' où ** i * répétitions ** devient ** i * stringLength **. – mginius

Questions connexes