【问题标题】:NSString (hex) to bytesNSString(十六进制)到字节
【发布时间】:2011-01-30 20:34:36
【问题描述】:

Objective-C 中是否有任何方法可以将十六进制字符串转换为字节?例如 @"1156FFCD3430AA22"unsigned char array {0x11, 0x56, 0xFF, ...}

【问题讨论】:

    标签: objective-c nsstring hex byte


    【解决方案1】:

    我能想到的最快的 NSString 类别实现(一些示例的鸡尾酒):

    - (NSData *)dataFromHexString {
        const char *chars = [self UTF8String];
        int i = 0, len = self.length;
    
        NSMutableData *data = [NSMutableData dataWithCapacity:len / 2];
        char byteChars[3] = {'\0','\0','\0'};
        unsigned long wholeByte;
    
        while (i < len) {
            byteChars[0] = chars[i++];
            byteChars[1] = chars[i++];
            wholeByte = strtoul(byteChars, NULL, 16);
            [data appendBytes:&wholeByte length:1];
        }
    
        return data;
    }
    

    它比 wookay 的解决方案快近 8 倍。 NSScanner 很慢。

    【讨论】:

    • +1 这似乎更好 - 不仅更快,而且这实际上是正确的。
    • 很好的实现,但是如果您需要错误检查,您需要在调用strtoul 之前将errno 设置为0,然后再读取它。
    • 为什么你把byteChars 设为 3 号而不是 2 号?
    • Nvm 我的 C 生锈了 - 忘记 C 字符串应该是空终止的。
    • @AnandPrakash 有什么可以帮忙的吗?您使用的是有效的十六进制字符串吗?长度应能被 2 整除,例如:@"AA11"
    【解决方案2】:
    @interface NSString (NSStringHexToBytes)
    -(NSData*) hexToBytes ;
    @end
    
    
    
    @implementation NSString (NSStringHexToBytes)
    -(NSData*) hexToBytes {
      NSMutableData* data = [NSMutableData data];
      int idx;
      for (idx = 0; idx+2 <= self.length; idx+=2) {
        NSRange range = NSMakeRange(idx, 2);
        NSString* hexStr = [self substringWithRange:range];
        NSScanner* scanner = [NSScanner scannerWithString:hexStr];
        unsigned int intValue;
        [scanner scanHexInt:&intValue];
        [data appendBytes:&intValue length:1];
      }
      return data;
    }
    @end
    
    
    
    /// example
    unsigned char bytes[] = { 0x11, 0x56, 0xFF, 0xCD, 0x34, 0x30, 0xAA, 0x22 };
    NSData* expectedData = [NSData dataWithBytes:bytes length:sizeof(bytes)];
    NSLog(@"data %@", [@"1156FFCD3430AA22" hexToBytes]);
    NSLog(@"expectedData isEqual:%d", [expectedData isEqual:[@"1156FFCD3430AA22" hexToBytes]]);
    

    【讨论】:

    • 如果我错了,请纠正我,但我认为 [data appendBytes:&intValue length:1] 有一些问题。 unsigned int 类型至少有四个字符宽(至少包含 32 位)。 &intValue 是指向四个中第一个的指针。这意味着在小端系统上 &intValue 将正确地成为指向您刚刚扫描的字符的指针。但在大端架构上,它总是指向零值,因为该值存储为四个字符中的最后一个。基本上这意味着这段代码可以在 Mac 上运行并在 iOS 上中断。
    • 这个答案有很多缺陷。它不仅将int 视为一个字节(根据C 标准这是不可能的),而且它只是多余地生成了很多子字符串,而不是仅仅遍历const char * 可以使用@987654324 获得@...
    【解决方案3】:

    scanHexInt:NSScanner 的类似方法可能有助于执行您想要的操作,但您可能需要先将字符串分成更小的块,在这种情况下手动进行翻译可能比手动翻译更简单使用NSScanner

    【讨论】:

      【解决方案4】:

      不是你现在做的那样。您需要编写自己的方法来获取每两个字符,将它们解释为 int,并将它们存储在数组中。

      【讨论】:

        【解决方案5】:

        修改方法,

        /* Converts a hex string to bytes.
         Precondition:
         . The hex string can be separated by space or not.
         . the string length without space or 0x, must be even. 2 symbols for one byte/char
         . sample input: 23 3A F1 OR 233AF1, 0x23 0X231f 2B
         */
        
        + (NSData *) dataFromHexString:(NSString*)hexString
        {
            NSString * cleanString = [Util cleanNonHexCharsFromHexString:hexString];
            if (cleanString == nil) {
                return nil;
            }
        
            NSMutableData *result = [[NSMutableData alloc] init];
        
            int i = 0;
            for (i = 0; i+2 <= cleanString.length; i+=2) {
                NSRange range = NSMakeRange(i, 2);
                NSString* hexStr = [cleanString substringWithRange:range];
                NSScanner* scanner = [NSScanner scannerWithString:hexStr];
                unsigned int intValue;
                [scanner scanHexInt:&intValue];
                unsigned char uc = (unsigned char) intValue;
                [result appendBytes:&uc length:1];
            }
            NSData * data = [NSData dataWithData:result];
            [result release];
            return data;
        }
        
        /* Clean a hex string by removing spaces and 0x chars.
         . The hex string can be separated by space or not.
         . sample input: 23 3A F1; 233AF1; 0x23 0x3A 0xf1
         */
        
        + (NSString *) cleanNonHexCharsFromHexString:(NSString *)input
        {
            if (input == nil) {
                return nil;
            }
        
            NSString * output = [input stringByReplacingOccurrencesOfString:@"0x" withString:@""
                                            options:NSCaseInsensitiveSearch range:NSMakeRange(0, input.length)];
            NSString * hexChars = @"0123456789abcdefABCDEF";
            NSCharacterSet *hexc = [NSCharacterSet characterSetWithCharactersInString:hexChars];
            NSCharacterSet *invalidHexc = [hexc invertedSet];
            NSString * allHex = [[output componentsSeparatedByCharactersInSet:invalidHexc] componentsJoinedByString:@""];
            return allHex;
        }
        

        【讨论】:

          【解决方案6】:

          在 Swift 2.2 中的首次尝试:

          func hexStringToBytes(hexString: String) -> NSData? {
              guard let chars = hexString.cStringUsingEncoding(NSUTF8StringEncoding) else { return nil}
              var i = 0
              let length = hexString.characters.count
          
              let data = NSMutableData(capacity: length/2)
              var byteChars: [CChar] = [0, 0, 0]
          
              var wholeByte: CUnsignedLong = 0
          
              while i < length {
                  byteChars[0] = chars[i]
                  i+=1
                  byteChars[1] = chars[i]
                  i+=1
                  wholeByte = strtoul(byteChars, nil, 16)
                  data?.appendBytes(&wholeByte, length: 1)
              }
          
              return data
          }
          

          或者,作为字符串的扩展:

          extension String {
          
              func dataFromHexString() -> NSData? {
                  guard let chars = cStringUsingEncoding(NSUTF8StringEncoding) else { return nil}
                  var i = 0
                  let length = characters.count
          
                  let data = NSMutableData(capacity: length/2)
                  var byteChars: [CChar] = [0, 0, 0]
          
                  var wholeByte: CUnsignedLong = 0
          
                  while i < length {
                      byteChars[0] = chars[i]
                      i+=1
                      byteChars[1] = chars[i]
                      i+=1
                      wholeByte = strtoul(byteChars, nil, 16)
                      data?.appendBytes(&wholeByte, length: 1)
                  }
          
                  return data
              }
          }
          

          这是一项持续进行中的工作,但目前看来运行良好。

          更多优化和更深入的讨论可以在Code Review找到。

          【讨论】:

          【解决方案7】:

          如果这样的字符串有几种解决方案返回错误的值 “DBA

          DBA”字符串的正确数据是"\x0D\xBA"(int值:3514)

          如果你得到的数据不是这样的"\x0D\xBA"这意味着你得到一个错误的字节,因为值会不同,例如你得到这样的数据" \xDB\x0A" int 值为 56074

          这里是重写解决方案:

          + (NSData *)dataFromHexString:(NSString *) string {
              if([string length] % 2 == 1){
                  string = [@"0"stringByAppendingString:string];
              }
          
              const char *chars = [string UTF8String];
              int i = 0, len = (int)[string length];
          
              NSMutableData *data = [NSMutableData dataWithCapacity:len / 2];
              char byteChars[3] = {'\0','\0','\0'};
              unsigned long wholeByte;
          
              while (i < len) {
                  byteChars[0] = chars[i++];
                  byteChars[1] = chars[i++];
                  wholeByte = strtoul(byteChars, NULL, 16);
                  [data appendBytes:&wholeByte length:1];
              }
              return data;
          
          }
          

          【讨论】:

            猜你喜欢
            • 2012-09-08
            • 2015-04-06
            • 1970-01-01
            • 2017-09-13
            • 2015-08-08
            • 2023-03-14
            • 1970-01-01
            • 2012-01-24
            相关资源
            最近更新 更多