57 votes

Comment convertir un NSData en une chaîne de caractères NSString en format hexadécimal ?

Lorsque j'appelle -description sur un objet NSData, je vois une jolie chaîne Hexadécimale des octets de l'objet NSData comme :

J'aimerais obtenir cette représentation des données (moins les guillemets lt/gt) dans un NSString en mémoire pour pouvoir travailler avec.. Je préférerais ne pas appeler -[NSData description] et ensuite simplement supprimer les guillemets lt/gt (car je suppose que ce n'est pas un aspect garanti de l'interface publique de NSData et est susceptible de changer à l'avenir).

Quel est le moyen le plus simple d'obtenir cette représentation d'un objet NSData dans un objet NSString (autre que d'appeler -description)?

1 votes

Alors, pourquoi pas de description? (Vraiment curieux. Je soupçonne que j'apprendrai quelque chose.)

1 votes

@Steven: La sortie de description peut changer selon les versions du système. Par exemple, -[NSDate description] était, avant Lion, documenté comme renvoyant une chaîne exactement dans le même format que celui requis pour -[NSDate initWithString:]; cette garantie n'est plus donnée. Discussion succincte ici: stackoverflow.com/questions/5837777/…

3 votes

description devrait être utilisé uniquement à des fins de débogage, car vous n'avez aucune garantie que la valeur retournée par la méthode description ne changera pas dans les futures versions (même si c'est peu probable). Par exemple, rien ne vous dit qu'Apple ne décidera pas un jour que si [NSData longueur]>200, alors la chaîne retournée par description sera tronquée au milieu... ou quelque chose de similaire. C'est pourquoi il peut ne pas être une bonne pratique de se fier à ce qui est retourné par description pour autre chose que le débogage/l'enregistrement.

93voto

Erik Aigner Points 7182

Gardez à l'esprit que toute solution String (format: ...) sera terriblement lente (pour des données volumineuses)

NSData *data = ...;
NSUInteger capacity = data.length * 2;
NSMutableString *sbuf = [NSMutableString stringWithCapacity:capacity];
const unsigned char *buf = data.bytes;
NSInteger i;
for (i=0; i

`Si vous avez besoin de quelque chose de plus performant essayez ceci :

static inline char itoh(int i) {
    if (i > 9) return 'A' + (i - 10);
    return '0' + i;
}

NSString * NSDataToHex(NSData *data) {
    NSUInteger i, len;
    unsigned char *buf, *bytes;

    len = data.length;
    bytes = (unsigned char*)data.bytes;
    buf = malloc(len*2);

    for (i=0; i> 4) & 0xF);
        buf[i*2+1] = itoh(bytes[i] & 0xF);
    }

    return [[NSString alloc] initWithBytesNoCopy:buf
                                          length:len*2
                                        encoding:NSASCIIStringEncoding
                                    freeWhenDone:YES];
}

Version Swift

private extension Data {
    var hexadecimalString: String {
        let charA: UInt8 = 0x61
        let char0: UInt8 = 0x30
        func byteToChar(_ b: UInt8) -> Character {
            Character(UnicodeScalar(b > 9 ? charA + b - 10 : char0 + b))
        }
        let hexChars = flatMap {[
            byteToChar(($0 >> 4) & 0xF),
            byteToChar($0 & 0xF)
        ]}
        return String(hexChars)
    }
}`

0 votes

Je pense que var p = UnsafeMutablePointer.alloc(length * 2) peut être let p = ... (via avertissement du compilateur Swift 2)

1 votes

Cela valait la peine de venir ici juste pour apprendre sur Chaîne(bytesNoCopy:longueur:encodage:). Les performances sont excellentes...j'ai appris quelques choses.

0 votes

Si vous êtes un développeur qui utilise Realm, vous pouvez utiliser ceci pour obtenir la clé de chiffrement du trousseau.

30voto

AliSoftware Points 21493

Je suis d'accord sur la solution de ne pas appeler description qui doit être réservé au débogage, donc bon point et bonne question :)

La solution la plus simple est de parcourir les octets du NSData et de construire la NSString à partir de ceux-ci. Utilisez [yourData bytes] pour accéder aux octets, et construisez la chaîne dans un NSMutableString.

Voici un exemple en implémentant ceci en utilisant une catégorie de NSData

@interface NSData(Hex)
-(NSString*)hexRepresentationWithSpaces_AS:(BOOL)spaces;
@end

@implementation NSData(Hex)
-(NSString*)hexRepresentationWithSpaces_AS:(BOOL)spaces
{
    const unsigned char* bytes = (const unsigned char*)[self bytes];
    NSUInteger nbBytes = [self length];
    //Si spaces est vrai, insérez un espace tous les ces nombreux octets d'entrée (deux fois ces nombreux caractères de sortie).
    static const NSUInteger spaceEveryThisManyBytes = 4UL;
    //Si spaces est vrai, insérez un saut de ligne au lieu d'un espace tous les ces espaces.
    static const NSUInteger lineBreakEveryThisManySpaces = 4UL;
    const NSUInteger lineBreakEveryThisManyBytes = spaceEveryThisManyBytes * lineBreakEveryThisManySpaces;
    NSUInteger strLen = 2*nbBytes + (spaces ? nbBytes/spaceEveryThisManyBytes : 0);

    NSMutableString* hex = [[NSMutableString alloc] initWithCapacity:strLen];
    for(NSUInteger i=0; i

`Utilisation :

NSData* data = ...
NSString* hex = [data hexRepresentationWithSpaces_AS:YES];`

1 votes

Nitpick: Si vous voulez correspondre à la description, vous voudriez "%02x", plutôt que "%02X". (La différence est minuscule vs. majuscule.)

1 votes

Beau extrait. Je l'ai rendu disponible en tant que gist avec des modifications mineures ici: gist.github.com/1443455

0 votes

Quand j'utilise cette solution, la valeur hexadécimale 90 ressort en tant que ffffff90. Qu'est-ce qui se passe avec ça?

22voto

MattDiPasquale Points 23842

J'ai préféré la réponse de @Erik_Aigner. Je l'ai juste un peu refactorée :

NSData *data = [NSMutableData dataWithBytes:"acani" length:5];
NSUInteger dataLength = [data length];
NSMutableString *string = [NSMutableString stringWithCapacity:dataLength*2];
const unsigned char *dataBytes = [data bytes];
for (NSInteger idx = 0; idx < dataLength; ++idx) {
    [string appendFormat:@"%02x", dataBytes[idx]];
}

3voto

Kevin Ballard Points 88866

Malheureusement, il n'y a pas de moyen intégré de produire une valeur hexadécimale à partir d'un NSData, mais il est assez facile de le faire vous-même. La façon simple est de passer simplement des octets successifs dans sprintf("%02x") et d'accumuler ceux-ci dans un NSMutableString. Une manière plus rapide serait de construire une table de recherche qui mappe 4 bits sur un caractère hexadécimal, puis de passer des nybbles successifs dans cette table.

1 votes

Pas besoin d'utiliser sprintf; NSMutableString a appendFormat:.

2voto

Dave Gallagher Points 5314

J'ai écrit une catégorie NSData en NSString hexadécimal que vous pouvez trouver ici: http://stackoverflow.com/a/9084784/153040

C'est similaire à la réponse de AliSoftware.

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