Objective c 将部分UTF-8解码为NSString

Objective c 将部分UTF-8解码为NSString,objective-c,ios,utf-8,nsstring,nsurlconnection,Objective C,Ios,Utf 8,Nsstring,Nsurlconnection,在使用NSURLConnection类通过网络获取UTF-8编码文件时,很有可能代理的连接:didReceiveData:消息将与截断UTF-8文件的NSData一起发送,因为UTF-8是一种多字节编码方案,一个字符可以在两个单独的NSData 换句话说,如果我将从connection:didReceiveData:获得的所有数据合并在一起,我将拥有一个有效的UTF-8文件,但每个单独的数据都无效UTF-8() 我不想将所有下载的文件都存储在内存中 我想要的是:给定NSData,将任何可以解码的

在使用
NSURLConnection
类通过网络获取
UTF-8
编码文件时,很有可能代理的
连接:didReceiveData:
消息将与截断
UTF-8
文件的
NSData
一起发送,因为
UTF-8
是一种多字节编码方案,一个字符可以在两个单独的
NSData

换句话说,如果我将从
connection:didReceiveData:
获得的所有数据合并在一起,我将拥有一个有效的
UTF-8
文件,但每个单独的数据都无效
UTF-8
()

我不想将所有下载的文件都存储在内存中

我想要的是:给定
NSData
,将任何可以解码的内容解码为
NSString
。万一最后 告诉我,
NSData
的几个字节是未关闭的代理项,因此我可以将它们保存到下一个
NSData


一个显而易见的解决方案是反复尝试使用
initWithData:encoding:
进行解码,每次都会截断最后一个字节,直到成功。不幸的是,这可能是非常浪费的。

UTF-8是一个非常简单的解析编码,它被设计成便于检测不完整的序列,如果你从一个不完整的序列中间开始,找到它的开始。
从末尾向后搜索一个0xc0字节。如果是=0xf0,则需要三个以下字节完成。

如果要确保在UTF-8多字节序列的中间不停止,则需要查看字节数组的末尾并检查前2位。
  • 如果顶部的位是0,那么它是一个ASCII样式的未转换UTF-8代码,您就完成了
  • 如果顶部位为1,从顶部开始的第二个位为0,则它是转义序列的延续,可能表示该序列的最后一个字节,因此您需要为以后缓冲字符,然后查看前面的字符*
  • 如果顶部位为1,从顶部开始的第二个位也为1,则它是多字节序列的开始,您需要通过查找第一个0位来确定序列中有多少个字符
  • 查看Wikipedia条目中的多字节表:

    //假设receivedData同时包含剩余数据和新数据
    无符号字符*数据=[receivedData字节];
    UInteger字节计数=[receivedData长度];
    if(字节数0)&&(lastByte&0xc0==0x80)){
    倒计时++;
    字节计数--;
    lastByte=数据[byteCount-1];
    }
    //此时,要么耗尽字节数,要么获得初始字符
    //如果我们耗尽字节数,我们可能处于非法序列中,这是我们应该做的
    //在receivedData中始终具有初始字符
    
    如果(字节数我有一个类似的问题-部分解码utf8

    以前

      NSString * adsTopic = [components[2] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
        adsInfo->adsTopic = malloc(sizeof(char) * adsTopic.length + 1);
        strncpy(adsInfo->adsTopic, [adsTopic UTF8String], adsTopic.length + 1);
    
    在[解决]之后

      NSString *adsTopic = [components[2] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
        NSUInteger byteCount = [adsTopic lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
        NSLog(@"number of Unicode characters in the string topic == %lu",(unsigned long)byteCount);
    
        adsInfo->adsTopic = malloc(byteCount+1);
        strncpy(adsInfo->adsTopic, [adsTopic UTF8String], byteCount + 1);
    
        NSString *text=[NSString stringWithCString:adsInfo.adsTopic encoding:NSUTF8StringEncoding];
                    NSLog(@"=== %@", text);
    

    谢谢你的回答!(同时我意识到这就是解决方案)-我相信代码本身有一些缺点。(1)我认为
    数据[byteCount]
    是不允许的,(2)
    数据
    不一定包含代理项的开头。我建议为后代进行修复。我修复了一个错误,oops。至于不包含代理项开头的可能性,除非数据有错误(并且有检查),或者在调用此函数之前,您应该将以前的数据放在receivedData的开头(开头有注释)。因此,数据不应该包含序列的结尾而不是开头。同意,我的错误。再次感谢!
      NSString *adsTopic = [components[2] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
        NSUInteger byteCount = [adsTopic lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
        NSLog(@"number of Unicode characters in the string topic == %lu",(unsigned long)byteCount);
    
        adsInfo->adsTopic = malloc(byteCount+1);
        strncpy(adsInfo->adsTopic, [adsTopic UTF8String], byteCount + 1);
    
        NSString *text=[NSString stringWithCString:adsInfo.adsTopic encoding:NSUTF8StringEncoding];
                    NSLog(@"=== %@", text);