解决NSData中包含非法UTF-8编码

转载 2015年07月06日 16:31:35

转自:http://www.tanhao.me/code/150608.html/(老谭)
本文仅给自己作为参考,如详细内容还请看原作
我们开发中常会遇上将NSData转换为NSString,或通过NSJSONSerialization解析JSON的场景,一旦NSData中包含非法的UTF-8编码,那么结果将是返回nil,但这样的结果并不符合我们预期,因为可能这其中仅仅只是一个编码错误,我们更希望将错误编码丢弃或替换为错误字符.
在Google上找了一圈,有人也实现了这样的方法,但个人觉得写得不够严谨,容错性也不太好,索性自己写一个吧,严格按照RFC3629的标准.

UTF-8是一种变长的编码,针对不同长度的字节有固定的格式,在RFC3629规范中最多只能四个字节,且对范围有区间有要求,更多相关介绍请跳转维基百科UTF-8词条(跳转地址):

1字节 0xxxxxxx
2字节 110xxxxx 10xxxxxx
3字节 1110xxxx 10xxxxxx 10xxxxxx
4字节 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
按照这样的规则写了一个NSData的扩展方法,见代码:

@implementation NSData (UTF8)

- (NSData *)UTF8Data
{
    //保存结果
    NSMutableData *resData = [[NSMutableData alloc] initWithCapacity:self.length];

    //无效编码替代符号(常见 � □ ?)
    NSData *replacement = [@"�" dataUsingEncoding:NSUTF8StringEncoding];

    uint64_t index = 0;
    const uint8_t *bytes = self.bytes;

    while (index < self.length)
    {
        uint8_t len = 0;
        uint8_t header = bytes[index];

        //单字节
        if ((header&0x80) == 0)
        {
            len = 1;
        }
        //2字节(并且不能为C0,C1)
        else if ((header&0xE0) == 0xC0)
        {
            if (header != 0xC0 && header != 0xC1)
            {
                len = 2;
            }
        }
        //3字节
        else if((header&0xF0) == 0xE0)
        {
            len = 3;
        }
        //4字节(并且不能为F5,F6,F7)
        else if ((header&0xF8) == 0xF0)
        {
            if (header != 0xF5 && header != 0xF6 && header != 0xF7)
            {
                len = 4;
            }
        }

        //无法识别
        if (len == 0)
        {
            [resData appendData:replacement];
            index++;
            continue;
        }

        //检测有效的数据长度(后面还有多少个10xxxxxx这样的字节)
        uint8_t validLen = 1;
        while (validLen < len && index+validLen < self.length)
        {
            if ((bytes[index+validLen] & 0xC0) != 0x80)
                break;
            validLen++;
        }

        //有效字节等于编码要求的字节数表示合法,否则不合法
        if (validLen == len)
        {
            [resData appendBytes:bytes+index length:len];
        }else
        {
            [resData appendData:replacement];
        }

        //移动下标
        index += validLen;
    }

    return resData;
}

@end

在Github上的链接地址:https://github.com/tanhaogg/THCategory

相关文章推荐

iOS不同编码的转换

编码

iOS-NSData 转换为UTF-8得到空的解决方案

NSData *ticketData = [ticket subdataWithRange:NSMakeRange(2, ticket.length -2)];                    ...

iOS 开发中常用编码格式转化

常见的字符编码格式:各种字符编码介绍及关系 ASCII :(American Standard Code for Information Interchange,美国标准信息交换代码) 百度百科 U...

php去除调非法的utf8字符代码

function check($src, &$des) { var_dump($src); $len = strlen($src); $curr = 0; $index = 0; while ($cu...

字符串编码转换(GBK) NSString, char, NSData相互转化 从 GBK 转到 UTF-8

问题: 1、Java后台返回的数据编码为 GBK , 而xcode 端默认为UTF-8,所以,当iOS 手机端向java获取发送含有中文的数据时,数据显示为乱码。当iso手机端向java后台发送含有...

如何去除utf-8字符串里头的非法字符

在开发的过程中碰到了在utf-8的字符串里头有非法字符的问题,搜了下,有不少人遇到了相同的问题。 有iconv.open("UTF-8", UTF-8//IGNORE") Table 3-7. W...

不要执行用utf-8編碼,并且內容包含非拉丁字符的批处理脚本

今天些批处理脚本的时候,执行的时候提示乱码,并说不是内部或者外部命令,也不是可执行程序或者批处理。 我一看就认为是編碼问题,因为这个脚本确实是crlf换行,編碼是utf-8(without BOM)...
  • atmouse
  • atmouse
  • 2015年06月14日 17:34
  • 311
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:解决NSData中包含非法UTF-8编码
举报原因:
原因补充:

(最多只允许输入30个字)