可以 stringEncodingForData:encodingOptions:convertedString:usedLossyConversion: return NSUTF16StringEncoding 或 NSUTF32StringEncoding 吗?

Can stringEncodingForData:encodingOptions:convertedString:usedLossyConversion: return NSUTF16StringEncoding or NSUTF32StringEncoding?

我想知道调用 stringEncodingForData:encodingOptions:convertedString:usedLossyConversion: 是否可以 return NSUTF16StringEncodingNSUTF32StringEncoding 或它们的任何变体?

我问的原因是因为这个 documentation note on cStringUsingEncoding::

Special Considerations

UTF-16 and UTF-32 are not considered to be C string encodings, and should not be used with this method—the results of passing NSUTF16StringEncoding, NSUTF32StringEncoding, or any of their variants are undefined.

所以我知道不支持使用 UTF-16 或 UTF-32 创建 C 字符串,但我不确定是否尝试使用 字符串编码检测 stringEncodingForData:encodingOptions:convertedString:usedLossyConversion: 可以 return UTF-16 和 UTF-32 也可以。

一个示例场景(改编自 SSZipArchive.m)可能是:

// name is a null-terminated C string built with `fread` from stdio.h:
char *name = (char *)malloc(size_name + 1);
size_t read = fread(name, 1, size_name + 1, file);
name[size_name] = '[=12=]';

// dataName is the data object of name
NSData *dataName = [NSData dataWithBytes:(const void *)name length:sizeof(unsigned char) * size_name];

// stringName is the string object of dataName
NSString *stringName = nil;
NSStringEncoding encoding = [NSString stringEncodingForData:dataName encodingOptions:nil convertedString:&stringName usedLossyConversion:nil];

在上面的代码中,encoding 可以是 NSUTF16StringEncodingNSUTF32StringEncoding 或者它们的任何变体吗?


平台:macOS 10.10+、iOS8.0+、watchOS 2.0+、tvOS 9.0+。

是,如果字符串使用其中一种编码进行编码。关于 C 字符串的注释是特定于 C 字符串的。 NSString 不是 C 字符串,您描述的方法不适用于 C 字符串;它适用于可能以多种方式编码的任意数据。

举个例子:

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSData *data = [@"test" dataUsingEncoding:NSUTF16StringEncoding];
        NSStringEncoding encoding = [NSString stringEncodingForData:data
                                                    encodingOptions:nil
                                                    convertedString:nil
                                                usedLossyConversion:nil];
        NSLog(@"%ld == %ld", (unsigned long)encoding, 
                             (unsigned long)NSUTF16StringEncoding);
    }
    return 0;
}
// Output:   10 == 10

这就是说,在您的具体示例中,如果 name 确实如其所说,"a null-terminated C string," 则它永远不可能是 UTF-16,因为 C 字符串不能以 UTF- 编码16. C 字符串以 \0 结尾,\0 是 UTF-16 中非常常见的字符。但是,在没有看到更多代码的情况下,我不会赌这个评论是否准确。

如果你真正的问题是 "given an arbitrary c-string-safe encoding, is it possible that stringEncodingForData: will return a not-c-string-safe encoding," 那么答案是 "yes, it could, and it's definitely not promised that it won't even if it doesn't today." 如果你需要防止这种情况,我建议使用 NSStringEncodingDetectionSuggestedEncodingsKey...UseOnlySuggestedEncodingsKey 来强制它是您可以处理的编码。 (您也可以使用 ...DisallowedEncodingsKey 来防止特定的多字节编码,但这不会那么健壮。)