1. 首先要考虑将String转成一个bytes的数组, 每个汉字是3个bytes, 英文或者标点是1个byte.

2. 然后去判断一下每一个byte的前面几个bit, 看下面的表, 1个byte的字符, 就是英文跟标点, 它的第1个bit是0;

3. 重点是3个bytes的字符, 就是汉字, 或者说CJK, 它的第1个byte的前面4个bit, 是1110, 那么我们可以根据这个来判断.看起来好像下面的代码, 居然是java跟oc可以共用的  :)

if((bytes[i]>>4)==0x0E){
            highPos=(bytes[i]<<4)|((bytes[i+1]&0x3f)>>2);
            lowPos=((bytes[i+1]&0x03)<<6)|(bytes[i+2]&0x3f);
            //NSLog(@"highPos: %x lowPos: %x",highPos,lowPos);
            chnCodeArray[chnCodeIndex]=highPos;
            chnCodeArray[chnCodeIndex+1]=lowPos;
            
            chnCodeIndex=chnCodeIndex+2;
            i=i+3;
            
        }else if(bytes[i]>>7==0){
            chnCodeArray[chnCodeIndex]=0;

chnCodeArray[chnCodeIndex+1]=bytes[i];
            chnCodeIndex=chnCodeIndex+2;
            i++;
        }
chnCodeArray就是用来存放结果的byte的数组.

4. 根据协议包, 先发送字符串开始, 数据, 结束的数据包.

[self sendPackage:UTF8_CODE_TRANS_START_CMD withCmdNumber:number withLength:length];
[self sendUTF8Data:utf8Bytes];
[self sendPackage:UTF8_CODE_TRANS_END_CMD withCmdNumber:number withLength:length];

可以看得出, 分别发送cmdPackage跟dataPackage, 可以写得更好的, 希望在安卓的版本中有更好的设计方法.

5. 简单看一下, sendPackage这个方法:

for(int i=0;i<3;i++){
        UInt64  startTime=[[NSDate date] timeIntervalSince1970]*1000;
        if(packageType==UTF8_CODE_TRANS_START_CMD){
            _packageID=[self sendUTF8TransStartCMDPackage:cmdNumber withLength:length];
        }else if(packageType==UTF8_CODE_TRANS_END_CMD){
            _packageID=[self sendUTF8TransEndCMDPackage:cmdNumber withLength:length];
        }
        if([self waitForACK:startTime]){
            return;
        }
}

重试3次, 如果有ACK就算发送成功.

-(bool)waitForACK:(UInt64) startTime{
    [self readFFF1Value];
    while(_ack==0){
        UInt64  endTime=[[NSDate date] timeIntervalSince1970]*1000;
        if((endTime-startTime)>1000){
            NSLog(@"Over time");
            return 0;
        }
        if(_ack==1){
            //NSLog(@"ack==1");
            return 1;
        }
    }
    return 0;
}

sendUTF8TransStartCMDPackage方法的精髓是, 妈的, 自己看吧:

_packageSendingType.packageType=UTF8_CODE_TRANS_START_CMD;
    _packageSendingType.warningCode=cmdNumber;
    _packageSendingType.packageLength=length;
    
    int packageID=arc4random()%255;
    
    NSData *data=[_blePackageFactory createPackage:_packageSendingType withPackageID:packageID];
    
    [self writeCharFFF1:data];
    
    _ack=0;
    
    return packageID;

这里会返回一个随机产生的packageID, 因为app校验ack的时候, 要用到这个packageID.

-(void) checkACK:(NSData*)charValue{
    
    Byte byteBuffer[20];
    //NSLog(@"checkACK thread is: %@",[NSThread currentThread]);
    
    //NSLog(@"%d",(int)[notifObj length]);
    [charValue getBytes:byteBuffer length:20];
   
    if((byteBuffer[3]==_packageID)&&(byteBuffer[4]==TYPE_DATA_ACK)&&(byteBuffer[5]==ACK_YES)){
        _ack=1;
        NSLog(@"ACK check ok");    
        _transferErrorCount=0;    
        [[NSNotificationCenter defaultCenter] postNotificationName:@"BLECharValue" object:@"ACK!"];     
    }else{   
        _transferErrorCount++;   
        if(_transferErrorCount>5){       
            _transferErrorCount=0;
            [[NSNotificationCenter defaultCenter] postNotificationName:@"BLECharValue" object:@"传输错误"];         
        }else{
            
            //[self sendStartPackage];
            [self resendPackage];   
        }
    }
}

这个方法是在读取char值的回调中运行的, 所以用上了一个外部的全局变量, 叫_ack

6. 总结一下, 配合之前规定的通讯协议, 这个蓝牙通讯, 无非两种包, 一种是命令包, 即通讯开始, 通讯结束, 一种是数据的传输.

关键是中间有很多信息, 例如, 包ID, 校验码, 字符串编号, 开始位, 停止位, 诸如此类...

将UTF8编码的3字节中英文转成2字节中英文.的更多相关文章

  1. 【异常记录(六)】vs文件乱码:文件加载,使用Unicode(UTF-8)编码加载文件xxx时,有些字节已用Unicode替换字符替换。保存该文件将不会保留原始文件内容。

    VS2013偶遇这种情况,页面汉字编码出现乱码.  .... 按照网上查到的:   工具>选项>文本编辑器> 勾选了  然并卵,还是乱码... 其实炒鸡简单 用记事本打开另存为,选择 ...

  2. 如何将一个用utf-8编码的文本用java程序转换成ANSI编码的文本

    jdk有一个关于UTF-8的bug所以加了一句 br.skip(1); bugID: http://bugs.java.com/view_bug.do?bug_id=4508058 public st ...

  3. Java不同编码方式,中英文字符所占字节数

    测试代码 public class Test { public static void main(String[] args){ String[] charsetNames={ "UTF-8 ...

  4. 【Java】如何检测、替换4个字节的utf-8编码(此范围编码包含emoji表情)

    > 参考的优秀文章 1.十分钟搞清字符集和字符编码 2.Java中byte与16进制字符串的互相转换 3.[异常处理]Incorrect string value: '\xF0\x90\x8D\ ...

  5. 在 Perl看来, 字符串只有两种形式. 一种是octets, 即8位序列, 也就是我们通常说的字节数组. 另一种utf8编码的字符串, perl管它叫string. 也就是说: Perl只熟悉两种编

    在 Perl看来, 字符串只有两种形式. 一种是octets, 即8位序列, 也就是我们通常说的字节数组. 另一种utf8编码的字符串, perl管它叫string. 也就是说: Perl只熟悉两种编 ...

  6. python中文utf8编码后是占3个字符,unicode汉字为2字节

    一个中文utf8编码后是占3个字符,所以求长度的函数可以这样写 def str_len(str): try: row_l=len(str) utf8_l=len(str.encode('utf-8') ...

  7. 刨根究底字符编码之十一——UTF-8编码方式与字节序标记

    UTF-8编码方式与字节序标记 一.UTF-8编码方式 1. 接下来将分别介绍Unicode字符集的三种编码方式:UTF-8.UTF-16.UTF-32.这里先介绍应用最为广泛的UTF-8. 为满足基 ...

  8. 1个汉字在UTF-8编码占3个字节

    http://blog.csdn.net/ns_code/article/details/14162087 http://www.ruanyifeng.com/blog/2007/10/ascii_u ...

  9. ASCII、Unicode和UTF-8编码的区别;中英文混合截取

    ASCII编码是128个字符 中国把汉字编入GB2312,Shift_JIS/Euc-kr各国标准..... Unicode是为了解决各国乱码的,但浪费存储空间 UTF-8编码把一个Unicode字符 ...

随机推荐

  1. Oracle导入中文乱码解决办法

    Oracle导入中文乱码解决办法 一.确保各个客户端字符集的编码同服务器字符集编码一致 1-       确定sqlplus字符集编码,如果是windows设置环境变量. 2-       确保Sec ...

  2. eclipse打开jar包出现乱码问题解决方法

    今天做项目时候,用eclipse打开.class文件出现乱码问题.jar编码和本地编辑器编码格式不对造成的错误. 首先我们打开eclipse,点击菜单下的window-->preferences ...

  3. 56个睿智帅气貌美的CTO大牛陪你叨逼叨

    技术领域门槛高,苦读十年有时不如大牛一指点 可CTO级别的大牛何处找? 别急,别急 他们1月12日都去参加APICloud新品发布会了! (没图说啥子) 各路大牛们云集,不仅是为APICloud新品发 ...

  4. SSH项目练习的时候报错:[applicationContext.xml]: Invocation of init method failed;

    这里是控制台的报错信息:org.springframework.beans.factory.BeanCreationException: Error creating bean with name ' ...

  5. 10月26日 奥威Power-BI基于微软示例库(MSOLAP)快速制作管理驾驶舱 腾讯课堂开课啦

    本次课是基于olap数据源的案例实操课,以微软olap示例库Adventure Works为数据基础.        AdventureWorks示例数据库为一家虚拟公司的数据,公司背景为大型跨国生产 ...

  6. D3D标注动态避让

    原来也思考了该如何实现标注动态避让,认为必须得计算字符串所占的大小.如果在屏幕上要计算屏幕象素之类的东西. 今天总算找到了实现方法,在C# WorldWind中的KMLImporter类中有.关键是F ...

  7. UltraEdit常用配置&搭建Java/C开发环境

    一:个人使用UE期间总结了以下经常使用的配置 1.手动配置语法高亮 [高级]->[配置]->[编辑器显示]->[语法高亮]->[词语列表的完整路径]->[浏览]找到安装目 ...

  8. [转]MongoDB for Java】Java操作MongoDB

    原文地址: MongoDB for Java]Java操作MongoDB 开发环境: System:Windows IDE:eclipse.MyEclipse 8 Database:mongoDB 开 ...

  9. ofbiz进击 第一节。 新建自己的webapp项目

    创建一个webapp的过程更新下来项目(直接从svn上面切下来就好),要先ant clean 下,然后在重新ant下.一: start sheel here :ant create-component ...

  10. 启动一个线程是用run()还是start()?

    启动一个线程是用run()还是start()? 答:启动一个线程是调用start()方法,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由JVM调度并执行.这并不意味着线程就会立即运行.run ...