objective-c cocoa nsstring

objective c - Invertir texto NSString



objective-c cocoa (20)

¿Sería más rápido si solo iteraras más de la mitad de la cadena intercambiando los caracteres en cada extremo? Entonces, para una cadena de 5 caracteres, intercambias los caracteres 1 + 5, luego 2 + 4 y 3 no necesitan intercambiarse con nada.

NSMutableString *reversed = [original mutableCopyWithZone:NULL]; NSUInteger i, length; length = [reversed length]; for (i = 0; i < length / 2; i++) { // Store the first character as we''re going to replace with the character at the end // in the example, it would store ''h'' unichar startChar = [reversed characterAtIndex:i]; // Only make the end range once NSRange endRange = NSMakeRange(length - i, 1); // Replace the first character (''h'') with the last character (''i'') // so reversed now contains "ii" [reversed replaceCharactersInRange:NSMakeRange(i, 1) withString:[reversed subStringWithRange:endRange]; // Replace the last character (''i'') with the stored first character (''h) // so reversed now contains "ih" [reversed replaceCharactersInRange:endRange withString:[NSString stringWithFormat:@"%c", startChar]]; }

editar ----

Después de haber hecho algunas pruebas, la respuesta es No, es aproximadamente 6 veces más lenta que la versión que recorre todo. Lo que nos ralentiza es crear las NSStrings temporales para el método replaceCharactersInRange: withString. Aquí hay un método que crea solo un NSString manipulando los datos del personaje directamente y parece mucho más rápido en pruebas simples.

NSUInteger length = [string length]; unichar *data = malloc(sizeof (unichar) * length); int i; for (i = 0; i < length / 2; i++) { unichar startChar = [string characterAtIndex:i]; unichar endChar = [string characterAtIndex:(length - 1) - i]; data[i] = endChar; data[(length - 1) - i] = startChar; } NSString *reversed = [NSString stringWithCharacters:data length:length]; free(data);

He estado buscando en Google sobre cómo hacer esto, pero ¿cómo iba a revertir un NSString? Ej .: hola se convertiría en: ih

Estoy buscando la manera más fácil de hacer esto.

¡Gracias!

@Vince hice este método:

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

Conecté ese método a didendonexit de textfield1. Cuando hago clic en el botón hecho, no se invierte el texto, UILabel solo muestra el texto de UITextField que ingresé. ¿Qué está mal?


Agregue una categoría a NSString para poder invocar inversamente en cualquier NSString en el futuro de esta manera:

#import "NSString+Reverse.h" @implementation NSString (Reverse) -(NSString*)reverse { char* cstring = (char*)[self UTF8String]; int length = [self length]-1; int i=0; while (i<=length) { unichar tmp = cstring[i]; cstring[i] = cstring[length]; cstring[length] = tmp; i++; length--; } return [NSString stringWithCString:cstring encoding:NSUTF8StringEncoding]; } @end


Aquí hay una colección de categorías en Objective-C que revertirán tanto NSStrings como NSAttributedStrings (conservando los atributos de los caracteres): TextFlipKit

Por ejemplo:

NSString *example = @"Example Text"; NSString *reversed = example.tfk_reversed; NSLog(@"Reversed: %@", reversed); //prints ''Reversed: txeT elpmaxE''


Escribí una categoría sobre esa: D

//NSString+Reversed.h # import

// // NSString+Reversed.h // HTMLPageFormatter // Created by beit46 on 21.06.13. // @interface NSString (Reversed) - (NSString *)reversedString; @end

//NSString+Reversed.m

// // NSString+Reversed.m // HTMLPageFormatter // Created by beit46 on 21.06.13. #import "NSString+Reversed.h" @implementation NSString (Reversed) - (NSString *)reversedString { NSMutableString *reversedString = [NSMutableString stringWithCapacity:[self length]]; [self enumerateSubstringsInRange:NSMakeRange(0,[self length]) options:(NSStringEnumerationReverse | NSStringEnumerationByComposedCharacterSequences) usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) { [reversedString appendString:substring]; }]; return [reversedString copy]; } @end


Escribe un bucle simple para hacer eso:

// 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"

En tu caso:

// 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;


Invierta la cadena usando recursión:

@implementation NSString (Reversed) + (NSString *)reversedStringFromString:(NSString *)string { NSUInteger count = [string length]; if (count <= 1) { // Base Case return string; } else { NSString *lastLetter = [string substringWithRange:NSMakeRange(count - 1, 1)]; NSString *butLastLetter = [string substringToIndex:count - 1]; return [lastLetter stringByAppendingString:[self reversedStringFromString:butLastLetter]]; } } @end


La respuesta de jano es correcta. Desafortunadamente, crea una gran cantidad de objetos temporales innecesarios. Aquí hay una implementación mucho más rápida (más complicada) que básicamente hace lo mismo, pero usa los búferes memcpy y unichar para mantener las asignaciones de memoria al mínimo.

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

Probé esto en 100,000 cadenas de Unicode multibyte al azar con longitudes entre 1 y 128. Esta versión es aproximadamente 4-5 veces más rápida que la de jano.

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

El código de prueba está en https://gist.github.com/prachigauriar/9739805 .

Actualización : Intenté esto de nuevo simplemente convirtiendo a un buffer UTF-32 y revirtiendo eso.

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

Esto es alrededor de 3-4 veces más rápido que la versión memcpy. La esencia antes mencionada ha sido actualizada con la última versión del código.

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


Ninguna de las respuestas parece considerar caracteres multibyte así que aquí está mi código de muestra. Asume que solo pasas una cadena más de un caracter.

- (void)testReverseString:(NSString *)string { NSMutableString *rString = [NSMutableString new]; NSInteger extractChar = [string length] - 1; while (extractChar >= 0) { NSRange oneCharPos = [string rangeOfComposedCharacterSequenceAtIndex:extractChar]; for (NSUInteger add = 0; add < oneCharPos.length; ++ add) { unichar oneChar = [string characterAtIndex:oneCharPos.location + add]; [rString appendFormat:@"%C", oneChar]; } extractChar -= oneCharPos.length; } NSLog(@"%@ becomes %@", string, encryptedString ); }


Pensé que lanzaría otra versión por si a alguien le interesara ... personalmente, me gusta el enfoque más limpio usando NSMutableString, pero si el rendimiento es la más alta prioridad, este es más rápido:

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

También escribí una prueba rápida para comparar esto con el método NSMutableString más tradicional (que también incluí a continuación):

// 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);

Los resultados fueron:

  • usando el método NSMutableString (abajo) - "revertido en 3.720631 segundos"

  • usando el método de buffer unichar * (arriba) - "invertido en 0.032604 segundos"

Solo como referencia, aquí está el método NSMutableString utilizado para esta comparación:

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


Rápido:

let string = "reverse" let reversedStringCollection = string.characters.reversed() for character in reversedStringCollection { reversedString.append(character) print(reversedString) }


También podemos lograr la secuencia inversa de la siguiente manera.

NSString *originalString = @"Hello"; NSString *reverseString; for (NSUInteger index = originalString.length; index > 0; index--) { char character = [originalString characterAtIndex:index]; reverseString = [reverseString stringByAppendingString:[NSString stringWithFormat:@"%c", character]]; }

o

NSString *originalString = @"Hello"; NSString *reverseString; for (NSUInteger index = originalString.length; index > 0; index--) { char *character = [originalString characterAtIndex:index]; reverseString = [reverseString stringByAppendingString:[NSString stringWithFormat:@"%s", character]]; }


Tengo dos soluciones simples para ese propósito:

+(NSString*)reverseString:(NSString *)str { NSMutableString* reversed = [NSMutableString stringWithCapacity:str.length]; for (int i = (int)str.length-1; i >= 0; i--){ [reversed appendFormat:@"%c", [str characterAtIndex:i]]; } return reversed; } +(NSString*)reverseString2:(NSString *)str { char* cstr = (char*)[str UTF8String]; int len = (int)str.length; for (int i = 0; i < len/2; i++) { char buf = cstr[i]; cstr[i] = cstr[len-i-1]; cstr[len-i-1] = buf; } return [[NSString alloc] initWithBytes:cstr length:len encoding:NSUTF8StringEncoding]; }

Ahora, vamos a probarlo!

NSString* str = @"Objective-C is a general-purpose, object-oriented programming language that adds Smalltalk-style messaging to the C programming language"; NSLog(@"REV 1: %@", [Util reverseString:str]); start = [NSDate date]; for (int i = 0 ; i < 1000; ++i) [Util reverseString:str]; end = [NSDate date]; NSLog(@"Time per 1000 repeats: %f", [end timeIntervalSinceDate:start]); NSLog(@"REV 2: %@", [Util reverseString2:str]); start = [NSDate date]; for (int i = 0 ; i < 1000; ++i) [Util reverseString2:str]; end = [NSDate date]; NSLog(@"Time per 1000 repeats: %f", [end timeIntervalSinceDate:start]);

Resultados:

ConsoleTestProject[68292:303] REV 1: egaugnal gnimmargorp C eht ot gnigassem elyts-klatllamS sdda taht egaugnal gnimmargorp detneiro-tcejbo ,esoprup-lareneg a si C-evitcejbO ConsoleTestProject[68292:303] Time per 1000 repeats: 0.063880 ConsoleTestProject[68292:303] REV 2: egaugnal gnimmargorp C eht ot gnigassem elyts-klatllamS sdda taht egaugnal gnimmargorp detneiro-tcejbo ,esoprup-lareneg a si C-evitcejbO ConsoleTestProject[68292:303] Time per 1000 repeats: 0.002038

Y el resultado de más caracteres fue:

ConsoleTestProject[68322:303] chars: 1982 ConsoleTestProject[68322:303] Time 1 per 1000 repeats: 1.014893 ConsoleTestProject[68322:303] Time 2 per 1000 repeats: 0.024928

El mismo texto con las funciones anteriores:

ConsoleTestProject[68366:303] Time 1 per 1000 repeats: 0.873574 ConsoleTestProject[68366:303] Time 2 per 1000 repeats: 0.019300 ConsoleTestProject[68366:303] Time 3 per 1000 repeats: 0.342735 <-Vladimir Gritsenko ConsoleTestProject[68366:303] Time 4 per 1000 repeats: 0.584012 <- Jano

Por lo tanto, elige el rendimiento!


Use el método con cualquier objeto: NSString, NSNumber, etc.:

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

Método:

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

Iniciar sesión:

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


Versión de bloque

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


Google es tu amigo :

-(NSString *) reverseString { NSMutableString *reversedStr; int len = [self length]; // Auto released string reversedStr = [NSMutableString stringWithCapacity:len]; // Probably woefully inefficient... while (len > 0) [reversedStr appendString: [NSString stringWithFormat:@"%C", [self characterAtIndex:--len]]]; return reversedStr; }


Swift 2.0:

1) let str = "¡Hola, mundo!" let reversed = String (str.characters.reverse ()) print (invertido)

En breve:

String("This is a test string.".characters.reverse())

2)

let string = "This is a test string." let characters = string.characters let reversedCharacters = characters.reverse() let reversedString = String(reversedCharacters)

La manera corta:

String("This is a test string.".characters.reverse())

O

let string = "This is a test string." let array = Array(string) let reversedArray = array.reverse() let reversedString = String(reversedArray) The short way : String(Array("This is a test string.").reverse())

Probado en Play Ground:

import Cocoa //Assigning a value to a String variable var str = "Hello, playground" //Create empty character Array. var strArray:Character[] = Character[]() //Loop through each character in the String for character in str { //Insert the character in the Array variable. strArray.append(character) } //Create a empty string var reversedStr:String = "" //Read the array from backwards to get the characters for var index = strArray.count - 1; index >= 0;--index { //Concatenate character to String. reversedStr += strArray[index] }

La versión más corta:

var str = “Hello, playground” var reverseStr = “” for character in str { reverseStr = character + reverseStr }


-(NSString *) reverseString: (NSString *) string { NSMutableArray *letters = [[NSMutableArray alloc] init]; for (int i=0; i<[string length]; i++) [letters addObject: [string substringWithRange: NSMakeRange(i, 1)]]; NSArray *reversed = [[letters reverseObjectEnumerator] allObjects]; return [reversed componentsJoinedByString: @""]; }


NSMutableString *result = [NSMutableString stringWithString:@""]; for (long i = self.length - 1; i >= 0; i--) { [result appendFormat:@"%c", [self characterAtIndex:i]]; } return (NSString *)result;


str=@"india is my countery"; array1=[[NSMutableArray alloc] init]; for(int i =0 ;i<[str length]; i++) { NSString *singleCharacter = [NSString stringWithFormat:@"%c", [str characterAtIndex:i]]; [array1 addObject:singleCharacter]; } NSMutableString* theString = [NSMutableString string]; for (int i=[array1 count]-1; i>=0;i--){ [theString appendFormat:@"%@",[array1 objectAtIndex:i]]; }


  • NSString en char utf32 (siempre 32 bits (unsigned int))
  • Marcha atrás
  • char utf32 en NSString

+ (NSString *)reverseString3:(NSString *)str { unsigned int *cstr, buf, len = [str length], i; cstr = (unsigned int *)[str cStringUsingEncoding:NSUTF32LittleEndianStringEncoding]; for (i=0;i < len/2;i++) buf = cstr[i], cstr[i] = cstr[len -i-1], cstr[len-i-1] = buf; return [[NSString alloc] initWithBytesNoCopy:cstr length:len*4 encoding:NSUTF32LittleEndianStringEncoding freeWhenDone:NO]; }

Ejemplo: Apple_is  --->  si_elppA