解决NSData转NSString返回nil的问题

在使用initWithData等方法将NSData转换成NSString时,如果NSData的内容含有非encoding编码的字符,将会返回nil。

----------SDK文档如下-------------

- (instancetype)initWithData:(NSData *)data encoding:(NSStringEncoding)encoding;

Return Value

An NSString object initialized by converting the bytes in data into Unicode characters using encoding. The returned object may be different from the original receiver. Returns nil if the initialization fails for some reason (for example if data does not represent valid data for encoding).

-----------------------------


这个结果在很多时候可能并不是我们所希望的,比如在获取网页源码进行分析等方面,如果页面采用了utf-8编码,只是含有个别非utf-8字符,我们更希望转换NSString成功,抛弃(或替换)那些非法字符。


按照utf8格式标准

Unicode/UCS-4
bit数
UTF-8
byte数
范围(16进制)
0000 ~
007F
0~7
0XXX XXXX
1
0x - 7x
0080 ~
07FF
8~11
110X XXXX
10XX XXXX
2
Cx 8x - Dx Bx
0800 ~
FFFF
12~16
1110XXXX
10XX XXXX
10XX XXXX
3
Ex 8x 8x - Ex Bx Bx
1 0000 ~
1F FFFF
17~21
1111 0XXX
10XX XXXX
10XX XXXX
10XX XXXX
4
F8 8x 8x 8x 8x - FB Bx Bx Bx Bx 
20 0000 ~
3FF FFFF
22~26
1111 10XX
10XX XXXX
10XX XXXX
10XX XXXX
10XX XXXX
5
FC 8x 8x 8x 8x 8x - FD Bx Bx Bx Bx Bx
400 0000 ~
7FFF FFFF
27~31
1111 110X
10XX XXXX
10XX XXXX
10XX XXXX
10XX XXXX
10XX XXXX
6


如果一个字节小于0x80,那么他就是一个字符;

如果大于C0小于E0,表示2个字节组成的utf8字符(第一个是110开头的,第二个是10开头的);

如果大于E0小于F0,表示3个字节组成的utf8字符(第一个是1110开头的,第二个是10开头的,第三个是10开头的);

以此类推,如果不符合utf-8规则,则表示一个非法字符,只要替换这样的字符即可。 


实现方法如下(此实现可用但不够严谨,如用于工程中建议进行优化):

//替换非utf8字符
//注意:如果是三字节utf-8,第二字节错误,则先替换第一字节内容(认为此字节误码为三字节utf8的头),然后判断剩下的两个字节是否非法;
- (NSData *)replaceNoUtf8:(NSData *)data
{
    char aa[] = {'A','A','A','A','A','A'};                      //utf8最多6个字符,当前方法未使用
    NSMutableData *md = [NSMutableData dataWithData:data];
    int loc = 0;
    while(loc < [md length])
    {
        char buffer;
        [md getBytes:&buffer range:NSMakeRange(loc, 1)];
        if((buffer & 0x80) == 0)
        {
            loc++;
            continue;
        }
        else if((buffer & 0xE0) == 0xC0)
        {
            loc++;
            [md getBytes:&buffer range:NSMakeRange(loc, 1)];
            if((buffer & 0xC0) == 0x80)
            {
                loc++;
                continue;
            }
            loc--;
            //非法字符,将这个字符(一个byte)替换为A
            [md replaceBytesInRange:NSMakeRange(loc, 1) withBytes:aa length:1];
            loc++;
            continue;
        }
        else if((buffer & 0xF0) == 0xE0)
        {
            loc++;
            [md getBytes:&buffer range:NSMakeRange(loc, 1)];
            if((buffer & 0xC0) == 0x80)
            {
                loc++;
                [md getBytes:&buffer range:NSMakeRange(loc, 1)];
                if((buffer & 0xC0) == 0x80)
                {
                    loc++;
                    continue;
                }
                loc--;
            }
            loc--;
            //非法字符,将这个字符(一个byte)替换为A
            [md replaceBytesInRange:NSMakeRange(loc, 1) withBytes:aa length:1];
            loc++;
            continue;
        }
        else
        {
            //非法字符,将这个字符(一个byte)替换为A
            [md replaceBytesInRange:NSMakeRange(loc, 1) withBytes:aa length:1];
            loc++;
            continue;
        }
    }
    
    return md;
}


转换后的NSData就可以正确转换为NSString了。


*如果是非utf-8编码,请自行对对应照编码协议转换。


  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
简单的http demo - (IBAction)get_btn_touch_up_inside:(id)sender { //K1+车次+K2 NSString *url=[K1 stringByAppendingString:self.m_trainName.text]; url=[url stringByAppendingString:K2]; NSURL *urlRquest=[NSURL URLWithString:k4]; NSURLRequest *request=[NSURLRequest requestWithURL:urlRquest]; NSLog(@"get_begin");//开始get的方法发送数据最好写成GCD的方式 NSURLResponse *response=nil;//获取服务器的响应返回 NSError *error=nil;//获取错误的信息 NSData *data=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];//等到了要刷新界面 NSHTTPURLResponse *httpResponse=(NSHTTPURLResponse*)response; NSString *str=[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]; NSDictionary *dict=[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil]; NSLog(@"%@",str); } //post方法 - (IBAction)post_btn_touch_up_inside:(id)sender { NSString *strTrainCode=self.m_trainName.text;//获取火车车次代码 NSString *strUserId=@"";//用户id,不需要赋值 NSString *strURL=k4;//请求的URL地址 NSString *strBody=[NSString stringWithFormat:@"TrainCode=%@&UserIDR=%@",strTrainCode,strUserId];//表示后面 NSString *length=[NSString stringWithFormat:@"%d",[strBody length]]; NSMutableURLRequest *request=[[NSMutableURLRequest alloc]init];//客户端向服务端请求的类 [request setURL:[NSURL URLWithString:strURL]];//设置http地址 [request setHTTPMethod:@"POST"];//设置发送方法 [request setTimeoutInterval:10];//设置连接超时,默认240秒 [request setValue:length forHTTPHeaderField:@"Content-Length"];//设置数据长度 [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Contene-Type"];//设置数据格式 [request setHTTPBody:[strBody dataUsingEncoding:NSUTF8StringEncoding]];//设置携带的消息体,准备请求 NSURLResponse *response=nil;//获取服务器的响应返回 NSError *error=nil;//获取错误的信息 NSData *data=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];//等到了要刷新界面 NSHTTPURLResponse *httpResponse=(NSHTTPURLResponse*)response; NSString *str=[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"%@",str); self.m_textView.text=str; }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值