initWithData: encoding:NSUTF8StringEncoding return nil

  • 我们经常使用[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]将NSData数据以utf-8解码为字符串,但是如果NSData数据受损,则会返回nil,以下是苹果对该方法的解释。
    Returns nil if the initialization fails for some reason (for example if data does not represent valid data for encoding).

  • 解决办法是将受损的Byte找出来替换掉或者删掉。

  • 具体的查找原理可以参考这篇文章。十分钟搞清字符集和字符编码

  • 网上找的一段查找和替换代码。解决NSData转NSString返回nil的问题

  • 原帖代码有越界风险,我修改了一下并给代码做了注释。

//替换非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) //0xxx xxxx 1个Byte
        {
            loc++;
            continue;
        }
        else if ((buffer & 0xE0) == 0xC0) //110x xxxx 2个Byte
        {
            loc++; //此处可能越界,要判断
            if (loc >= md.length) { //此时的buffer已经是最后一个Byte
                loc--;
                //非法字符,将这个字符(一个byte)替换为A
                [md replaceBytesInRange:NSMakeRange(loc, 1) withBytes:aa length:1];
                break;
            }
            [md getBytes:&buffer range:NSMakeRange(loc, 1)];
            if ((buffer & 0xC0) == 0x80) //10xx xxxx 第2个Byte
            {
                loc++;
                continue;
            }
            loc--;
            //非法字符,将这个字符(一个byte)替换为A
            [md replaceBytesInRange:NSMakeRange(loc, 1) withBytes:aa length:1];
            loc++;
            continue;
        }
        else if ((buffer & 0xF0) == 0xE0) //1110 xxxx 3个Byte
        {
            loc++; //此处可能越界,要判断
            if (loc >= md.length) { //此时的buffer已经是最后一个Byte
                loc--;
                //非法字符,将这个字符(一个byte)替换为A
                [md replaceBytesInRange:NSMakeRange(loc, 1) withBytes:aa length:1];
                break;
            }
            [md getBytes:&buffer range:NSMakeRange(loc, 1)];
            if ((buffer & 0xC0) == 0x80) //10xx xxxx 第2个Byte
            {
                loc++; //此处可能越界,要判断
                if (loc >= md.length) { //此时的buffer已经是最后一个Byte
                    loc--;
                    //非法字符,将这个字符(一个byte)替换为A
                    [md replaceBytesInRange:NSMakeRange(loc, 1) withBytes:aa length:1];
                    break;
                }
                [md getBytes:&buffer range:NSMakeRange(loc, 1)];
                if ((buffer & 0xC0) == 0x80) //10xx xxxx 第3个Byte
                {
                    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;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • /**ios常见的几种加密方法: 普通的加密方法是讲密码进行加密后保存到用户偏好设置( [NSUserDefaul...
    彬至睢阳阅读 3,031评论 0 7
  • 面向对象三大支柱封装:就是把相关的数据和代码结合成一个有机的整体,形成数据和操作代码的封装体,对外只提供一个可以控...
    WangDavid阅读 1,727评论 0 2
  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,219评论 30 472
  • 技术无极限,从菜鸟开始,从源码开始。 由于公司目前项目还是用OC写的项目,没有升级swift 所以暂时SDWebI...
    充满活力的早晨阅读 12,704评论 0 2
  • 有人问你幸福吗?你思考了一会觉得幸福,而有些人会不加思索的回答,我不幸福。幸福不幸福的定义是什么呢?每个人都有一个...
    念追忆loveing阅读 224评论 0 2