macos 如何将 NSData 转换为 NSString Hex 字符串?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7520615/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 08:28:06  来源:igfitidea点击:

How to convert an NSData into an NSString Hex string?

macoscocoa

提问by Todd Ditchendorf

When I call -descriptionon an NSDataobject, I see a pretty Hex string of the NSDataobject's bytes like:

当我调用-description一个NSData对象时,我看到一个漂亮的NSData对象字节的十六进制字符串,例如:

<f6e7cd28 0fc5b5d4 88f8394b af216506 bc1bba86 4d5b483d>

I'd like to get this representation of the data (minus the lt/gt quotes) into an in-memory NSStringso I can work with it.. I'd prefer not to call -[NSData description]and then just trim the lt/gt quotes (because I assume that is not a guaranteed aspect of NSData's public interface and is subject change in the future).

我想将数据的这种表示(减去 lt/gt 引号)放入内存中,NSString以便我可以使用它..我不想调用-[NSData description]然后只修剪 lt/gt 引号(因为我认为这不是NSData的公共接口的保证方面,并且将来会发生变化)。

What's the simplest way to get this representation of an NSDataobject into an NSStringobject (other than calling -description)?

NSData对象的这种表示形式转换为NSString对象的最简单方法是什么(调用-description除外)?

回答by Erik Aigner

Keep in mind that any String(format: ...)solution will be terribly slow (for large data)

请记住,任何String(format: ...)解决方案都会非常慢(对于大数据)

NSData *data = ...;
NSUInteger capacity = data.length * 2;
NSMutableString *sbuf = [NSMutableString stringWithCapacity:capacity];
const unsigned char *buf = data.bytes;
NSInteger i;
for (i=0; i<data.length; ++i) {
  [sbuf appendFormat:@"%02X", (NSUInteger)buf[i]];
}

If you need something more performanttry this:

如果您需要更高性能的东西,请尝试以下操作:

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<len; i++) {
        buf[i*2] = itoh((bytes[i] >> 4) & 0xF);
        buf[i*2+1] = itoh(bytes[i] & 0xF);
    }

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

Swift 4.2 version

斯威夫特 4.2 版本

extension Data {

    var hexString: String? {
        return withUnsafeBytes { (bytes: UnsafePointer<UInt8>) in
            let charA = UInt8(UnicodeScalar("a").value)
            let char0 = UInt8(UnicodeScalar("0").value)

            func itoh(_ value: UInt8) -> UInt8 {
                return (value > 9) ? (charA + value - 10) : (char0 + value)
            }

            let hexLen = count * 2
            let ptr = UnsafeMutablePointer<UInt8>.allocate(capacity: hexLen)

            for i in 0 ..< count {
                ptr[i*2] = itoh((bytes[i] >> 4) & 0xF)
                ptr[i*2+1] = itoh(bytes[i] & 0xF)
            }

            return String(bytesNoCopy: ptr,
                               length: hexLen,
                             encoding: .utf8,
                         freeWhenDone: true)
        }
    }
}

回答by AliSoftware

I agree on the solution notto call descriptionwhich is to be reserved for debugging, so good point and good question :)

我同意调用的解决方案,description这是为调试保留的,所以好点和好问题:)

The easiest solution is to loop thru the bytes of the NSDataand construct the NSString from it. Use [yourData bytes]to access the bytes, and build the string into an NSMutableString.

最简单的解决方案是循环遍历 的字节NSData并从中构造 NSString。使用[yourData bytes]访问字节,并建立串入一个NSMutableString

Here is an example by implementing this using a category of NSData

这是一个使用 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];
    //If spaces is true, insert a space every this many input bytes (twice this many output characters).
    static const NSUInteger spaceEveryThisManyBytes = 4UL;
    //If spaces is true, insert a line-break instead of a space every this many spaces.
    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<nbBytes; ) {
        [hex appendFormat:@"%02X", bytes[i]];
        //We need to increment here so that the every-n-bytes computations are right.
        ++i;

        if (spaces) {
            if (i % lineBreakEveryThisManyBytes == 0) [hex appendString:@"\n"];
            else if (i % spaceEveryThisManyBytes == 0) [hex appendString:@" "];
        }
    }
    return [hex autorelease];
}
@end

Usage:

用法:

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

回答by Johannes Lund

Just wanted to add that @PassKits's method can be written very elegantly using Swift 3 since Datanow is a collection.

只是想补充一点,@PassKits 的方法可以使用 Swift 3 非常优雅地编写,因为Data现在是一个集合。

extension Data { 
    var hex: String {
        var hexString = ""
        for byte in self {
            hexString += String(format: "%02X", byte)
        }

        return hexString
    }
}

Or ...

或者 ...

extension Data {
    var hex: String {
        return self.map { b in String(format: "%02X", b) }.joined()
    }
}

Or even ...

甚至 ...

extension Data {
    var hex: String {
        return self.reduce("") { string, byte in
            string + String(format: "%02X", byte)
        }
    }
}

回答by ma11hew28

I liked @Erik_Aigner's answer the best. I just refactored it a bit:

我最喜欢@Erik_Aigner 的回答。我只是重构了一下:

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

回答by PassKit

In Swift you can create an extension.

在 Swift 中,您可以创建扩展。

extension NSData {

    func toHexString() -> String {

        var hexString: String = ""
        let dataBytes =  UnsafePointer<CUnsignedChar>(self.bytes)

        for (var i: Int=0; i<self.length; ++i) {
            hexString +=  String(format: "%02X", dataBytes[i])
        }

        return hexString
    }
}

Then you can simply use:

然后你可以简单地使用:

let keyData: NSData = NSData(bytes: [0x00, 0xFF], length: 2)

let hexString = keyData.toHexString()
println("\(hexString)") // Outputs 00FF

回答by Lily Ballard

Sadly there's no built-in way to produce hex from an NSData, but it's pretty easy to do yourself. The simple way is to just pass successive bytes into sprintf("%02x") and accumulate those into an NSMutableString. A faster way would be to build a lookup table that maps 4 bits into a hex character, and then pass successive nybbles into that table.

遗憾的是,没有内置的方法可以从 NSData 生成十六进制,但是自己很容易做到。简单的方法是将连续字节传递给 sprintf("%02x") 并将它们累积到 NSMutableString 中。一种更快的方法是构建一个查找表,将 4 位映射到一个十六进制字符,然后将连续的 nybbles 传递到该表中。

回答by Steve Streza

While it may not be the most efficient way to do it, if you're doing this for debugging, SSCrypto has a category on NSData which contains two methods to do this (one for creating an NSString of the raw byte values, and one which shows a prettier representation of it).

虽然这可能不是最有效的方法,但如果您这样做是为了调试,SSCrypto 在 NSData 上有一个类别,其中包含两种方法(一种用于创建原始字节值的 NSString,另一种用于显示了它的更漂亮的表示)。

http://www.septicus.com/SSCrypto/trunk/SSCrypto.m

http://www.septicus.com/SSCrypto/trunk/SSCrypto.m

回答by pheuberger

Seeing there is a Swift 1.2 snippet in the comments, here's the Swift 2 version since C style for loops are deprecated now. Gistwith MIT license and two simple unit tests if you care.

看到评论中有一个 Swift 1.2 片段,这里是 Swift 2 版本,因为现在不推荐使用 C 风格的 for 循环。 吉斯特与MIT许可证,如果你关心两个简单的单元测试。

Here's the code for your convenience:

为了您的方便,这是代码:

import Foundation

extension NSData {
  var hexString: String {
    let pointer = UnsafePointer<UInt8>(bytes)
    let array = getByteArray(pointer)

    return array.reduce("") { (result, byte) -> String in
      result.stringByAppendingString(String(format: "%02x", byte))
    }
  }

  private func getByteArray(pointer: UnsafePointer<UInt8>) -> [UInt8] {
    let buffer = UnsafeBufferPointer<UInt8>(start: pointer, count: length)

    return [UInt8](buffer)
  }
}