NSData转换为NSString失败,原因是一些字符。

3

我正在使用以下方法将作为url响应得到的NSData转换为NSString

NSString *result = [[NSString alloc] initWithData:_Data encoding:NSUTF8StringEncoding];

这个东西我用了很长时间,一直都运行良好。但今天在加载数据(分页)时遇到了问题,有一页的结果返回一个null字符串。

于是我在Stack Overflow上搜索并从这个链接上找到了一个方法:NSData转NSString的问题!

[NSString stringWithCString:[theData bytes] length:[theData length]];

这个代码能正常工作。

我的疑问:

  1. 这个方法在iOS 2.0中被弃用了。如果我现在使用它,将来会有什么问题吗?
  2. 我认为是这段文本导致了该方法的失效enter image description here。这是什么,有没有办法使用NSUTF8StringEncoding对其进行编码?
  3. 有哪些备选编码可以用于对上述图片中的所有字符类型进行编码?
4个回答

4
为了获取服务器发送的内容类型,您需要检查响应的Content-Type头部。
内容类型的值指定了一个"MIMI类型",例如: Content-Type: text/plain Content-Type的值还可以指定字符编码,例如: Content-Type: text/plain; charset=utf-8 每种MIME类型都应定义一个"默认"字符集,在未指定字符集参数时使用该字符集。
对于text/*媒体类型,默认字符集是US-ASCII。(请参见RFC 6657, §3)。
以下代码片段演示了如何安全地编码响应的主体内容:
    - (NSString*) bodyString {
        CFStringEncoding cfEncoding = NSASCIIStringEncoding;
        NSString* textEncodingName = self.response.textEncodingName;
        if (textEncodingName) {
            cfEncoding = CFStringConvertIANACharSetNameToEncoding( (__bridge CFStringRef)(textEncodingName) );
        }
        if (cfEncoding != kCFStringEncodingInvalidId) {
            NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(cfEncoding);
            return [[NSString alloc] initWithData:self.body encoding:encoding];
        }        
        else {
            return [self.body description];
        }
    }

注意: body 是一个返回表示响应数据的 NSData 对象的属性。 response 是一个返回 NSHTTPURLResponse 对象的属性。

这是一个很好的通用解决方案,我之前不知道CFStringConvertIANACharSetNameToEncoding()! - Martin R
更好的解决方案应该考虑到以前已经过时的文本*媒体类型的默认编码:ISO-8859-1。也就是说,当没有指定字符集并且US-ASCII失败时,可以尝试使用ISO-8859-1,然后再回退到原始二进制。 - CouchDeveloper
为什么不先尝试使用ISO-8859-1(又称NSISOLatin1StringEncoding)(如果未指定字符集)?据我所知,这是US-ASCII的扩展,并且任意字节流的转换从不失败,因为所有字节0x00..0xFF都映射到U+00..U+FF中相应的字符。 - Martin R
是的,这是一个有效的选项 - 就像任何其他US-ASCII兼容编码(UTF-8)一样。您是否要这样做只取决于随后的“字符串处理器”,它可能只能理解US-ASCII。如果您只想将其显示或记录到控制台,则可以将其编码为ISO-8859-1或UTF-8(或者使用“有损ASCII转换”)。否则,如果您想检查数据是否确实是US-ASCII,则可以在不是时返回nil。最后,如果您需要保持字节流不变(例如用于解析器),只需使用NSData对象,而无需使用NSString。 - CouchDeveloper
谢谢@CouchDeveloper,我一定会尝试这个解决方案。目前我已经将服务器用户设置为UTF-8编码。对你的回答点赞。 - vamsi575kg

2
如果
NSString *result = [[NSString alloc] initWithData:_Data encoding:NSUTF8StringEncoding];

如果返回nil,则表示_Data不包含有效的UTF-8编码字符串。

你说过:

[NSString stringWithCString:[theData bytes] length:[theData length]];

在您的情况下,该方法可以正常工作。该方法将数据字节解释为“默认C字符串编码”,但未指定该编码是什么(因此此方法已弃用,不应使用)。

我认为默认的C字符串编码仍然是“Mac Roman”。在这种情况下,

NSString *result = [[NSString alloc] initWithData:_Data encoding:NSMacOSRomanStringEncoding];

这可能是正确的解决方案。但无论如何,您都应该找出Web服务在响应中使用的编码,并在initWithData:encoding:方法中指定。


@vamsi575kg 无论如何,服务器都应该设置适当的 Content-Type 头信息。Content-Type 头信息指定内容类型(例如图像、文本等)和其他属性,当内容为文本时可能有字符集。 - CouchDeveloper
@MartinR NSMacOSRomanStringEncoding 很可能是不正确的,因为发送数据的服务器不知道接收者当前平台字符串实现的默认编码是什么 ;) - CouchDeveloper
@CouchDeveloper:那只是一个猜测,基于OP的陈述,它在使用“stringWithCString”时运行良好。我刚刚测试了一下:该方法实际上使用了古老的Mac Roman编码。 - Martin R
@MartinR 是的,NSString 可能使用那种编码方式,但这是不相关的。需要的是从服务器发送的字节流的编码方式。这就是 NSString 创建时应该如何解释字节序列的方法。 - CouchDeveloper
@CouchDeveloper:OP说使用从服务器获取的数据调用[NSString stringWithCString:...]返回了正确的结果。如果是这样,那么服务器必须以Mac Roman编码发送数据。 - Martin R
显示剩余2条评论

0

试试这个

NSString *theString = [NSString stringWithFormat:@"To be continued%C", ellipsis];

NSData *asciiData = [theString dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];

NSString *asciiString = [[NSString alloc] initWithData:asciiData encoding:NSASCIIStringEncoding];

NSLog(@"Original: %@ (length %d)", theString, [theString length]);
NSLog(@"Converted: %@ (length %d)", asciiString, [asciiString length]);

这将把它转换为ASCII,而不是UTF8。 - Daniel

0

这是由于字符串编码不正确导致的。 您可以尝试以下方法:

  1. 使用 dataPathNSData 保存到磁盘上
  2. 使用 NSString 类方法创建字符串:
+ (id)stringWithContentsOfURL:(NSURL *)url usedEncoding:(NSStringEncoding *)enc error:(NSError **)error

请注意:

enc

如果成功读取url,则返回用于解释数据的编码。

因此,如果方法成功,您可以获得正确的字符串,并且所有操作都由iOS完成。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接