美文网首页
CFStringCreateWithBytes 提升异常容错性

CFStringCreateWithBytes 提升异常容错性

作者: yellowzhou | 来源:发表于2018-11-09 13:59 被阅读0次

在 iOS 开发中,经常会遇到编码问题,通过系统API转码时由于没有容错性,导致因为个别异常编码问题,让全部转码失败。

  • 在数据传递我们经常会采用base64 + gbk 方式,当在base64 转换成data时是没有问题的,主要是在转换gbk,如果里面存在个别使用UTF-8编码时,会导致转码失败,使用的接口如下:
CFStringRef CFStringCreateWithBytes(CFAllocatorRef alloc, const UInt8 *bytes, CFIndex numBytes, CFStringEncoding encoding, Boolean isExternalRepresentation);
  • 为解决上述问题,需要在转码异常时,把响应异常的编码数据剔除掉,然后再进行转码才可以解决,下面就是针对于GB18030编码异常数据的校验

检验GB18030 异常编码

  • 异常编码采用 ? 代替
unsigned int checkGB18030(const unsigned char *bytes, unsigned int length, unsigned char *buffer)
{
    unsigned int bufferIndex = 0;
    unsigned int byteIndex = 0;
    bool invalidByte = false;
    while (byteIndex < length) {
        Byte byte = bytes[byteIndex];
        if (byte >= 0 && byte <= (Byte)0x7f) {
            //单字节(英文、数字)
            buffer[bufferIndex++] = byte;
        } else if (byte >= (Byte)0x81 && byte <= (Byte)0xfe){
            //可能是双字节,可能是四字节
            if (byteIndex + 1 >= length) {
                //这是最后一个字节了,但是这个字节表明后面应该还有1或3个字节,那么这个字节一定是错误字节
                break;
            }
            
            Byte byte2 = bytes[++byteIndex];
            if (byte2 >= (Byte)0x40 && byte <= (Byte)0xfe && byte != (Byte)0x7f) {
                //是双字节,并且可能合法
                unsigned char tuple[] = {byte, byte2};
                CFStringRef cfstr = CFStringCreateWithBytes(kCFAllocatorDefault, tuple, 2, kCFStringEncodingGB_18030_2000, false);
                if (cfstr) {
                    CFRelease(cfstr);
                    buffer[bufferIndex++] = byte;
                    buffer[bufferIndex++] = byte2;
                } else {
                    //这个双字节字符不合法,但byte2可能是下一字符的第一字节
                    invalidByte = true;
                }
            } else if (byte2 >= (Byte)0x30 && byte2 <= (Byte)0x39) {
                //可能是四字节
                if (byteIndex + 2 >= length) {
                    break;
                }
                
                Byte byte3 = bytes[++byteIndex];
                if (byte3 >= (Byte)0x81 && byte3 <= (Byte)0xfe) {
                    // 第三位合法,判断第四位
                    
                    Byte byte4 = bytes[++byteIndex];
                    if (byte4 >= (Byte)0x30 && byte4 <= (Byte)0x39) {
                        //第四位可能合法
                        unsigned char tuple[] = {byte, byte2, byte3, byte4};
                        CFStringRef cfstr = CFStringCreateWithBytes(kCFAllocatorDefault, tuple, 4, kCFStringEncodingGB_18030_2000, false);
                        if (cfstr) {
                            CFRelease(cfstr);
                            buffer[bufferIndex++] = byte;
                            buffer[bufferIndex++] = byte2;
                            buffer[bufferIndex++] = byte3;
                            buffer[bufferIndex++] = byte4;
                        } else {
                            //这个四字节字符不合法,但是byte2可能是下一个合法字符的第一字节,回退3位
                            //并且将byte1,byte2用?替代
                            invalidByte = true;
                        }
                    } else {
                        //第四字节不合法
                        invalidByte = true;
                    }
                } else {
                    // 第三字节不合法
                    invalidByte = true;
                }
            } else {
                // 第二字节不是合法的第二位,但可能是下一个合法的第一位,所以回退一个byte
                invalidByte = true;
            }
            
            if (invalidByte) {
                invalidByte = false;
                buffer[bufferIndex++] = '?';
            }
        }
        byteIndex++;
        
    }
    return bufferIndex;
}
  • 返回值为正常编码的字节数
  • 返回数据通过buffer 传递出去

具体测试代码

void test()
{
    char *base64 = "CTxkaXY+us69KioKCQkJCQk8c3Bhbj4x";
    char buffer[1024] = {0};
    
    NSData *data64 = [NSData dataWithBytes:base64 length:strlen(base64)];
    NSData *decodeData = [GTMBase64 decodeData:data64];
    const unsigned char *bytes = (void *)[decodeData bytes];
    NSUInteger lenght = [decodeData length];
    printf("base64: %s",bytes);
    CFStringRef cfstr = CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8 *)bytes, lenght, kCFStringEncodingGB_18030_2000, false);
    if (cfstr) {
        NSString *text = (__bridge NSString *)cfstr;
        NSLog(@"%@",text);
        CFRelease(cfstr);
    } else {
        lenght = checkGB18030(bytes, (unsigned int)lenght, (unsigned char *)buffer);
        cfstr = CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8 *)buffer, lenght, kCFStringEncodingGB_18030_2000, false);
        if (cfstr) {
            NSString *text = (__bridge NSString *)cfstr;
            NSLog(@"%@",text);
            CFRelease(cfstr);
        } else {
            NSLog(@"解析错误!!!!");
        }
    }
}

测试结果

test.png

相关文章

  • CFStringCreateWithBytes 提升异常容错性

    在 iOS 开发中,经常会遇到编码问题,通过系统API转码时由于没有容错性,导致因为个别异常编码问题,让全部转码失...

  • 看看你的幸福指数高不高?

    容错性高,幸福指数也高。 容错性是计算机术语,表示软件出现异常后,从错误中恢复,继续正常运行的能力。今天看稿子的时...

  • 怎样编写健壮的代码

    怎样编写健壮的代码 代码的几种特性 鲁棒性Robust(健壮性) 系统在异常和危险情况下生存的关键 容错性 可移植...

  • 浅谈Python异常处理机制

    异常机制己经成为衡量一门编程语言是否成熟的标准之一,使用异常处理机制的 Python 程序有更好的容错性,更加健壮...

  • ES横向扩容

    图解横向扩容过程,如何超出扩容极限,以及如何提升容错性 (1)primary&replica自动负载均衡,6个sh...

  • 数据库常见的异常和错误

    空指针异常、指定类不存在异常、数学异常、非法参数异常、连接异常、数组下标越界异常。不兼容错误、连接错误、实例化错误...

  • 28.实现FallbackFactory容错获取异常

    实现FallbackFactory容错获取异常 第1步:编写ProductServiceFallbackFacto...

  • 04基于Hystrix的服务熔断和降级

    一 Hystrix理解 用于隔离访问远程系统、服务或者第三方库,防止级联失败,从而提升系统的可用性与容错性。 二 ...

  • 第33节:Java面向对象中的异常

    Java中的异常和错误 Java中的异常机制,更好地提升程序的健壮性 throwable为顶级,Error和Exc...

  • Spark面试题

    1. spark如何实现容错性? spark的容错性有2个手段, 检查点和RDD血统 检查点: checkpoin...

网友评论

      本文标题:CFStringCreateWithBytes 提升异常容错性

      本文链接:https://www.haomeiwen.com/subject/bmbnxqtx.html