El uso de Objective C / Cocoa para desactivar los caracteres Unicode, es decir, \ u1234

Algunos sitios de los que estoy obteniendo datos están devolviendo cadenas UTF-8, con los caracteres UTF-8 escapados, es decir: \u5404\u500b\u90fd

¿Existe una función de cocoa incorporada que pueda ayudar con esto o tendré que escribir mi propio algoritmo de deencoding?

No hay una función incorporada para hacer C unescaping.

Puede engañar un poco con NSPropertyListSerialization ya que un NSPropertyListSerialization “old text style” admite C escapando a través de \Uxxxx :

 NSString* input = @"ab\"cA\"BC\\u2345\\u0123"; // will cause trouble if you have "abc\\\\uvw" NSString* esc1 = [input stringByReplacingOccurrencesOfString:@"\\u" withString:@"\\U"]; NSString* esc2 = [esc1 stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""]; NSString* quoted = [[@"\"" stringByAppendingString:esc2] stringByAppendingString:@"\""]; NSData* data = [quoted dataUsingEncoding:NSUTF8StringEncoding]; NSString* unesc = [NSPropertyListSerialization propertyListFromData:data mutabilityOption:NSPropertyListImmutable format:NULL errorDescription:NULL]; assert([unesc isKindOfClass:[NSString class]]); NSLog(@"Output = %@", unesc); 

pero importa que esto no sea muy eficiente. Es mucho mejor si escribes tu propio analizador. (Por cierto, ¿estás decodificando cadenas JSON? En caso afirmativo, podrías utilizar los analizadores JSON existentes ).

Es correcto que Cocoa no ofrece una solución , pero Core Foundation sí lo hace: CFStringTransform .

CFStringTransform vive en una esquina polvorienta y remota de Mac OS (y iOS), por lo que es una pequeña joya. Es la interfaz del motor de transformación de cadenas compatible con ICU de Apple. Puede realizar magia real como transcripciones entre griego y latín (o sobre cualquier secuencia de comandos conocida), pero también se puede usar para realizar tareas mundanas como cortar cadenas de un servidor malo:

 NSString *input = @"\\u5404\\u500b\\u90fd"; NSString *convertedString = [input mutableCopy]; CFStringRef transform = CFSTR("Any-Hex/Java"); CFStringTransform((__bridge CFMutableStringRef)convertedString, NULL, transform, YES); NSLog(@"convertedString: %@", convertedString); // prints: 各個都, tada! 

Como dije, CFStringTransform es realmente poderoso. Es compatible con varias transformaciones predefinidas, como asignaciones de casos, normalizaciones o conversión de nombre de carácter unicode. Incluso puedes diseñar tus propias transformaciones.

No tengo idea de por qué Apple no lo hace disponible desde Cocoa.

Edición 2015:

OS X 10.11 e iOS 9 agregan el siguiente método a Foundation:

 - (nullable NSString *)stringByApplyingTransform:(NSString *)transform reverse:(BOOL)reverse; 

Entonces el ejemplo de arriba se convierte en …

 NSString *input = @"\\u5404\\u500b\\u90fd"; NSString *convertedString = [input stringByApplyingTransform:@"Any-Hex/Java" reverse:YES]; NSLog(@"convertedString: %@", convertedString); 

Gracias @nschmidt por el aviso .

Esto es lo que terminé escribiendo. Espero que esto ayude a algunas personas.

 + (NSString*) unescapeUnicodeString:(NSString*)string { // unescape quotes and backwards slash NSString* unescapedString = [string stringByReplacingOccurrencesOfString:@"\\\"" withString:@"\""]; unescapedString = [unescapedString stringByReplacingOccurrencesOfString:@"\\\\" withString:@"\\"]; // tokenize based on unicode escape char NSMutableString* tokenizedString = [NSMutableString string]; NSScanner* scanner = [NSScanner scannerWithString:unescapedString]; while ([scanner isAtEnd] == NO) { // read up to the first unicode marker // if a string has been scanned, it's a token // and should be appended to the tokenized string NSString* token = @""; [scanner scanUpToString:@"\\u" intoString:&token]; if (token != nil && token.length > 0) { [tokenizedString appendString:token]; continue; } // skip two characters to get past the marker // check if the range of unicode characters is // beyond the end of the string (could be malformed) // and if it is, move the scanner to the end // and skip this token NSUInteger location = [scanner scanLocation]; NSInteger extra = scanner.string.length - location - 4 - 2; if (extra < 0) { NSRange range = {location, -extra}; [tokenizedString appendString:[scanner.string substringWithRange:range]]; [scanner setScanLocation:location - extra]; continue; } // move the location pas the unicode marker // then read in the next 4 characters location += 2; NSRange range = {location, 4}; token = [scanner.string substringWithRange:range]; unichar codeValue = (unichar) strtol([token UTF8String], NULL, 16); [tokenizedString appendString:[NSString stringWithFormat:@"%C", codeValue]]; // move the scanner past the 4 characters // then keep scanning location += 4; [scanner setScanLocation:location]; } // done return tokenizedString; } + (NSString*) escapeUnicodeString:(NSString*)string { // lastly escaped quotes and back slash // note that the backslash has to be escaped before the quote // otherwise it will end up with an extra backslash NSString* escapedString = [string stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"]; escapedString = [escapedString stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""]; // convert to encoded unicode // do this by getting the data for the string // in UTF16 little endian (for network byte order) NSData* data = [escapedString dataUsingEncoding:NSUTF16LittleEndianStringEncoding allowLossyConversion:YES]; size_t bytesRead = 0; const char* bytes = data.bytes; NSMutableString* encodedString = [NSMutableString string]; // loop through the byte array // read two bytes at a time, if the bytes // are above a certain value they are unicode // otherwise the bytes are ASCII characters // the %C format will write the character value of bytes while (bytesRead < data.length) { uint16_t code = *((uint16_t*) &bytes[bytesRead]); if (code > 0x007E) { [encodedString appendFormat:@"\\u%04X", code]; } else { [encodedString appendFormat:@"%C", code]; } bytesRead += sizeof(uint16_t); } // done return encodedString; } 

código simple:

 const char *cString = [unicodeStr cStringUsingEncoding:NSUTF8StringEncoding]; NSString *resultStr = [NSString stringWithCString:cString encoding:NSNonLossyASCIIStringEncoding]; 

desde: https://stackoverflow.com/a/7861345