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


    我们开发中常会遇上将NSData转换为NSString,或通过NSJSONSerialization解析JSON的场景,一旦NSData中包含非法的UTF-8编码,那么结果将是返回nil,但这样的结果并不符合我们预期,因为可能这其中仅仅只是一个编码错误,我们更希望将错误编码丢弃或替换为错误字符.
    在Google上找了一圈,有人也实现了这样的方法,但个人觉得写得不够严谨,容错性也不太好,索性自己写一个吧,严格按照RFC3629的标准.

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

    1
    2
    3
    4
    1字节 0xxxxxxx
    2字节 110xxxxx 10xxxxxx
    3字节 1110xxxx 10xxxxxx 10xxxxxx
    4字节 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

    按照这样的规则写了一个NSData的扩展方法,见代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    @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

  • 相关阅读:
    java Android get date before 7 days (one week) Stack Overflow
    计算机网络与分布式系统实验室 北京大学
    得到IFrame中的Document
    eclipse如何把多个项目放在一个文件夹下
    windows 32位程序编译成64位
    iPhone5和iOS6上HTML5开发的新增功能
    Thinking in Java之接口回调改版
    Java学习笔记35:Java常用字符串操作函数
    进一步优化Bitmap Cache策略
    微软安全新闻聚焦双周刊第三十期
  • 原文地址:https://www.cnblogs.com/xiao-love-meng/p/5757564.html
Copyright © 2020-2023  润新知