将包含 UTF-8 和空字节的 NSData 转换为字符串

Converting NSData that contains UTF-8 and null bytes to string

我有一个 __NSCFData 对象。我知道里面是什么。

61 70 70 6c 65 2c 74 79 70 68 6f 6f 6e 00 41 52 4d 2c 76 38 00

我尝试使用 initWithData: 和 stringWithUTF8String: 将其转换为字符串,它给了我 "apple,typhoon"。转换终止于 00

实际数据是

61 a
70 p
70 p
6c l
65 e
2c ,
74 t
79 y
70 p
68 h
6f o
6f o
6e n
00 (null)
41 A
52 R
4d M
2c ,
76 v
38 8
00 (null)

如何在不丢失信息的情况下正确转换它?

0 或 null 是终止字符串的标记值,因此如果您想自动将字节转储到字符串中,您将不得不以某种方式处理它。如果不这样做,字符串或尝试打印它的东西,例如,将假定在到达 NULL 时已到达字符串末尾。

只需将出现的字节替换为可打印的内容,例如 space。使用适合您的值。

示例:

// original data you have from somewhere
char something[] = "apple,typhoon[=10=]ARM,v8[=10=]";
NSData *data = [NSData dataWithBytes:something length:sizeof(something)];

// Find each null terminated string in the data
NSMutableArray *strings = [NSMutableArray new];
NSMutableString *temp = [NSMutableString string];
const char *bytes = [data bytes];
for (int i = 0; i < [data length]; i++) {
    unsigned char byte = (unsigned char)bytes[i];
    if (byte == 0) {
        if ([temp length] > 0) {
            [strings addObject:temp];
            temp = [NSMutableString string];
        }
    } else {
        [temp appendFormat:@"%c", byte];
    }
}

// Results
NSLog(@"strings count: %lu", [strings count]);
[strings enumerateObjectsUsingBlock:^(NSString *string, NSUInteger idx, BOOL * _Nonnull stop) {
    NSLog(@"%ld: %@", idx, string);
}];
// strings count: 2
// 0: apple,typhoon
// 1: ARM,v8

stringWithUTF8String 的文档将其第一个参数描述为:

A NULL-terminated C array of bytes in UTF8 encoding.

这就是为什么您的转换在第一个空字节处停止的原因。

您似乎拥有的是一组打包成单个 NSData 的 C 字符串。您可以单独转换每一个。使用NSData方法byteslength分别获取指向bytes/firstC字符串的指针和总字节数。标准 C 函数 strlen() 将为您提供单个字符串的字节长度。结合这些和一些简单的指针算法,您可以编写一个循环来转换每个字符串,例如,将它们全部存储到一个数组中或连接它们。

如果您在实施解决方案时遇到困难,请提出一个新问题,展示您的代码并解释问题。下一步肯定会有人帮助你。

HTH

与某些答案的意图相反,NSString 实例中存储的字符串 不是 0 终止的。即使写出它们可能存在问题(因为用于输出的底层 C 函数需要一个以 0 结尾的字符串),实例本身也可以包含 [=13=]:

NSString *zeroIncluded = @"A[=10=]B";
NSLog(@"%ld", [zeroIncluded length]);
// prints 3

要创建这样的实例,您可以使用具有 byteslength 参数的方法,即。 e. -initWithBytes:length:encoding:。因此,这样的事情应该有效:

NSData *data = …
[[NSString alloc] initWithBytes:[data bytes] length:[data length] encoding:NSUTF8StringEncoding];

但是,按照 CRD 的意图,您可能会检查是否需要这样的字符串。