Convertir NSData codificado en UTF-8 a NSString


Tengo codificado UTF-8 NSData desde Windows Server y quiero convertirlo a NSString para iPhone. Dado que los datos contienen caracteres (como un símbolo de grado) que tienen valores diferentes en ambas plataformas, ¿cómo convierto los datos en cadena?

Author: Bhavin Ramani, 2010-03-18

6 answers

Si los datos no están terminados en null, debe usar -initWithData:encoding:

NSString* newStr = [[NSString alloc] initWithData:theData encoding:NSUTF8StringEncoding];

Si los datos están terminados en null, debería usar -stringWithUTF8String: para evitar el \0 extra al final.

NSString* newStr = [NSString stringWithUTF8String:[theData bytes]];

(Tenga en cuenta que si la entrada no está correctamente codificada en UTF-8, obtendrá nil.)


Variante rápida:

let newStr = String(data: data, encoding: .utf8)
// note that `newStr` is a `String?`, not a `String`.

Si los datos están terminados en null, podría ir a través de la forma segura que es eliminar el carácter nulo, o la forma insegura similar a la versión de Objective-C arriba.

// safe way, provided data is \0-terminated
let newStr1 = String(data: data.subdata(in: 0 ..< data.count - 1), encoding: .utf8)
// unsafe way, provided data is \0-terminated
let newStr2 = data.withUnsafeBytes(String.init(utf8String:))
 1122
Author: kennytm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-25 09:32:42

Puedes llamar a este método

+(id)stringWithUTF8String:(const char *)bytes.
 28
Author: Gouldsc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-12 05:42:00

Humildemente presento una categoría para que esto sea menos molesto:

@interface NSData (EasyUTF8)

// Safely decode the bytes into a UTF8 string
- (NSString *)asUTF8String;

@end

Y

@implementation NSData (EasyUTF8)

- (NSString *)asUTF8String {
    return [[NSString alloc] initWithData:self encoding:NSUTF8StringEncoding];    
}

@end

(Tenga en cuenta que si no está utilizando ARC necesitará un autorelease allí.)

Ahora en lugar de lo horriblemente detallado:

NSData *data = ...
[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

Puedes hacer:

NSData *data = ...
[data asUTF8String];
 19
Author: Claudiu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-20 15:19:09

La versión de Swift de String a Data y de vuelta a String:

Xcode 9 * Swift 4

extension Data {
    var string: String {
        return String(data: self, encoding: .utf8) ?? ""
    }
}
extension String {
    var data: Data {
        return Data(utf8)
    }
    var base64Decoded: Data? {
        return Data(base64Encoded: self)
    }
}

Parque infantil

let string = "Hello World"                                  // "Hello World"
let stringData = string.data                                // 11 bytes
let base64EncodedString = stringData.base64EncodedString()  // "SGVsbG8gV29ybGQ="
let stringFromData = stringData.string                      // "Hello World"

let base64String = "SGVsbG8gV29ybGQ="
if let data = base64String.base64Decoded {
    print(data)                                    //  11 bytes
    print(data.base64EncodedString())              // "SGVsbG8gV29ybGQ="
    print(data.string)                             // "Hello World"
}

let stringWithAccent = "Olá Mundo"                          // "Olá Mundo"
print(stringWithAccent.count)                               // "9"
let stringWithAccentData = stringWithAccent.data            // "10 bytes" note: an extra byte for the acute accent
let stringWithAccentFromData = stringWithAccentData.string  // "Olá Mundo\n"
 16
Author: Leo Dabus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-15 10:43:00

A veces, los métodos en las otras respuestas no funcionan. En mi caso, estoy generando una firma con mi clave privada RSA y el resultado es NSData. Encontré que esto parece funcionar:

Objective-C

NSData *signature;
NSString *signatureString = [signature base64EncodedStringWithOptions:0];

Swift

let signatureString = signature.base64EncodedStringWithOptions(nil)
 14
Author: mikeho,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-20 15:27:16

Solo para resumir, aquí hay una respuesta completa, que funcionó para mí.

Mi problema fue que cuando usé

[NSString stringWithUTF8String:(char *)data.bytes];

La cadena que obtuve era impredecible: Alrededor del 70% contenía el valor esperado, pero con demasiada frecuencia resultó con Null o aún peor: garbaged al final de la cadena.

Después de algunas excavaciones cambié a

[[NSString alloc] initWithBytes:(char *)data.bytes length:data.length encoding:NSUTF8StringEncoding];

Y obtuvo el resultado esperado cada vez.

 1
Author: Gal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-29 18:52:25