51 votes

Inverser le texte NSString

J'ai beaucoup cherché sur Google comment faire, mais comment inverser une NSString ? Ex : hi deviendrait : ih

Je cherche le moyen le plus simple de le faire.

Merci !

@Vince j'ai fait cette méthode :

- (IBAction)doneKeyboard {

// first retrieve the text of textField1
NSString *myString = field1.text;
NSMutableString *reversedString = [NSMutableString string];
NSUInteger charIndex = 0;
while(myString && charIndex < [myString length]) {
    NSRange subStrRange = NSMakeRange(charIndex, 1);
    [reversedString appendString:[myString substringWithRange:subStrRange]];
    charIndex++;
}
// reversedString is reversed, or empty if myString was nil
field2.text = reversedString;
}

J'ai relié cette méthode au didendonexit de textfield1. Lorsque je clique sur le bouton "done", le texte n'est pas inversé, l'UILabel affiche simplement le texte du UITextField que j'ai saisi. Quel est le problème ?

103voto

Jano Points 37593

Version bloc.

NSString *myString = @"abcdefghijklmnopqrstuvwxyz";
NSMutableString *reversedString = [NSMutableString stringWithCapacity:[myString length]];

[myString enumerateSubstringsInRange:NSMakeRange(0,[myString length]) 
                             options:(NSStringEnumerationReverse | NSStringEnumerationByComposedCharacterSequences)
                          usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
                            [reversedString appendString:substring];
                        }];

// reversedString is now zyxwvutsrqponmlkjihgfedcba

54voto

Écrivez une boucle simple pour faire cela :

// myString is "hi"
NSMutableString *reversedString = [NSMutableString string];
NSInteger charIndex = [myString length];
while (charIndex > 0) {
    charIndex--;
    NSRange subStrRange = NSMakeRange(charIndex, 1);
    [reversedString appendString:[myString substringWithRange:subStrRange]];
}
NSLog(@"%@", reversedString); // outputs "ih"

Dans votre cas :

// first retrieve the text of textField1
NSString *myString = textField1.text;
NSMutableString *reversedString = [NSMutableString string];
NSInteger charIndex = [myString length];
while (myString && charIndex > 0) {
    charIndex--;
    NSRange subStrRange = NSMakeRange(charIndex, 1);
    [reversedString appendString:[myString substringWithRange:subStrRange]];
}
// reversedString is reversed, or empty if myString was nil
textField2.text = reversedString;

11voto

Prachi Gauriar Points 31

La réponse de Jano est correcte. Malheureusement, elle crée beaucoup d'objets temporaires inutiles. Voici une implémentation beaucoup plus rapide (et plus compliquée) qui fait essentiellement la même chose, mais qui utilise memcpy et des tampons unichar pour limiter au maximum les allocations de mémoire.

- (NSString *)reversedString
{
    NSUInteger length = [self length];
    if (length < 2) {
        return self;
    }

    unichar *characters = calloc(length, sizeof(unichar));
    unichar *reversedCharacters = calloc(length, sizeof(unichar));
    if (!characters || !reversedCharacters) {
        free(characters);
        free(reversedCharacters);
        return nil;
    }

    [self getCharacters:characters range:NSMakeRange(0, length)];

    NSUInteger i = length - 1;
    NSUInteger copiedCharacterCount = 0;

    // Starting from the end of self, copy each composed character sequence into reversedCharacters
    while (copiedCharacterCount < length) {
        NSRange characterRange = [self rangeOfComposedCharacterSequenceAtIndex:i];
        memcpy(reversedCharacters + copiedCharacterCount, characters + characterRange.location, characterRange.length * sizeof(unichar));
        i = characterRange.location - 1;
        copiedCharacterCount += characterRange.length;
    }

    free(characters);

    NSString *reversedString = [[NSString alloc] initWithCharactersNoCopy:reversedCharacters length:length freeWhenDone:YES];
    if (!reversedString) {
        free(reversedCharacters);
    }

    return reversedString;
}

Je l'ai testé sur 100 000 chaînes Unicode multi-octets aléatoires dont la longueur est comprise entre 1 et 128. Cette version est environ 4-5x plus rapide que celle de jano.

Enumerate substrings: 2.890528
MemCopy: 0.671090
Enumerate substrings: 2.840411
MemCopy: 0.662882

Le code de test est à https://gist.github.com/prachigauriar/9739805 .

Mise à jour : J'ai essayé à nouveau en convertissant simplement vers un tampon UTF-32 et en inversant cela.

- (NSString *)qlc_reversedStringWithUTF32Buffer
{
    NSUInteger length = [self length];
    if (length < 2) {
        return self;
    }

    NSStringEncoding encoding = NSHostByteOrder() == NS_BigEndian ? NSUTF32BigEndianStringEncoding : NSUTF32LittleEndianStringEncoding;
    NSUInteger utf32ByteCount = [self lengthOfBytesUsingEncoding:encoding];
    uint32_t *characters = malloc(utf32ByteCount);
    if (!characters) {
        return nil;
    }

    [self getBytes:characters maxLength:utf32ByteCount usedLength:NULL encoding:encoding options:0 range:NSMakeRange(0, length) remainingRange:NULL];

    NSUInteger utf32Length = utf32ByteCount / sizeof(uint32_t);
    NSUInteger halfwayPoint = utf32Length / 2;
    for (NSUInteger i = 0; i < halfwayPoint; ++i) {
        uint32_t character = characters[utf32Length - i - 1];
        characters[utf32Length - i - 1] = characters[i];
        characters[i] = character;
    }

    return [[NSString alloc] initWithBytesNoCopy:characters length:utf32ByteCount encoding:encoding freeWhenDone:YES];
}

C'est environ 3-4 fois plus rapide que la version memcpy. Le gist mentionné ci-dessus a été mis à jour avec la dernière version du code.

Enumerate substrings: 2.168705
MemCopy: 0.488320
UTF-32: 0.150822
Enumerate substrings: 2.169655
MemCopy: 0.481786
UTF-32: 0.147534
Enumerate substrings: 2.248812
MemCopy: 0.505995
UTF-32: 0.154531

8voto

jpage4500 Points 1

Je me suis dit que j'allais proposer une autre version au cas où cela intéresserait quelqu'un Personnellement, je préfère l'approche plus propre utilisant NSMutableString mais si les performances sont la priorité absolue, celle-ci est plus rapide :

- (NSString *)reverseString:(NSString *)input {
    NSUInteger len = [input length];
    unichar *buffer = malloc(len * sizeof(unichar));
    if (buffer == nil) return nil; // error!
    [input getCharacters:buffer];

    // reverse string; only need to loop through first half
    for (NSUInteger stPos=0, endPos=len-1; stPos < len/2; stPos++, endPos--) {
        unichar temp = buffer[stPos];
        buffer[stPos] = buffer[endPos];
        buffer[endPos] = temp;
    }

    return [[NSString alloc] initWithCharactersNoCopy:buffer length:len freeWhenDone:YES];
}

J'ai également écrit un test rapide pour comparer cette méthode avec la méthode plus traditionnelle NSMutableString (que j'ai également incluse ci-dessous) :

// test reversing a really large string
NSMutableString *string = [NSMutableString new];
for (int i = 0; i < 10000000; i++) {
    int digit = i % 10;
    [string appendFormat:@"%d", digit];
}
NSTimeInterval startTime = [[NSDate date] timeIntervalSince1970];
NSString *reverse = [self reverseString:string];
NSTimeInterval elapsedTime = [[NSDate date] timeIntervalSince1970] - startTime;
NSLog(@"reversed in %f secs", elapsedTime);

Les résultats étaient :

  • en utilisant la méthode NSMutableString (ci-dessous) - "inversé en 3,720631 secondes".

  • en utilisant la méthode *buffer d'unichar (ci-dessus) - "inversé en 0,032604 secondes".

À titre de référence, voici la méthode NSMutableString utilisée pour cette comparaison :

- (NSString *)reverseString:(NSString *)input {
    NSUInteger len = [input length];
    NSMutableString *result = [[NSMutableString alloc] initWithCapacity:len];
    for (int i = len - 1; i >= 0; i--) {
        [result appendFormat:@"%c", [input characterAtIndex:i]];
    }
    return result;
}

3voto

Utilisez la méthode avec n'importe quel objet : NSString,NSNumber,etc.. :

NSLog(@"%@",[self reverseObject:@12345]);
NSLog(@"%@",[self reverseObject:@"Hello World"]);

Méthode :

-(NSString*)reverseObject:(id)string{

string = [NSString stringWithFormat:@"%@",string];
NSMutableString *endString = [NSMutableString new];

while ([string length]!=[endString length]) {
    NSRange range = NSMakeRange([string length]-[endString length]-1, 1);
    [endString appendString: [string substringWithRange:range]];
}
return endString;}

Journal :

2014-04-16 11:20:25.312 TEST[23733:60b] 54321
2014-04-16 11:20:25.313 TEST[23733:60b] dlroW olleH

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X