由谈退格键的实现来学习字符编码
我曾以为老师的话是真的,我曾以为老师会为自己说出的话负责,但事实证明很多时候是照本宣科。
这次在公司做Fcitx输入法时,想到退格删除的字节数的不同,即退格键一按到底删除的是一个字节还是两个字节或者多个。在测试中我发现,中文汉字占了三个字节,竟然占了三个字节,老师不是经常告诉我们汉字是占两个字节,但现在怎么占了三个字节,是老师的错还是程序的错,亦或本都没错,只是没有探其根本罢了。
说汉字占两个字节是从以Unicode的编码方式UCS-2来说的,但实际占三个字节,是从Unicode的实现方式UTF-8来说的。
先介绍下Unicode字符集吧。
什么是字符?什么是字符集?
字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。
字符集是多个字符的集合,字符集种类较多,每个字符集合包含的字符个数不同,常见字符集名称:ASCII字符集、Unicode字符集、GB2312字符集、BIG5字符集、GB18030字符集等。
多年来,许多人一直将文本串作为一系列单字节字符来进行编码,并在结尾处放一个零。对于我们来说,很习惯调用strlen函数来返回以0结尾的单字节字符数组中字符数目。这是我们平时所说的ASCII字符,即单字节字符,一个字符占一个字节,即八位,所以它提供的符号最多不能超过1+28-1=256个字符,但明显单字节是根本不够用的,为此出现了双字节字符集(DBCS)。
Unicode的编码和实现。
大概来说,Unicode编码系统可分为编码方式和实现方式两个层次。
编码方式
Unicode是国际组织制定的可以容纳世界上所以文字和符号的字符编码方案。Unicode用数字0-0x10FFFF来映射这些字符,最多可以容纳1114112个字符,或者说有1114112个码位。码位就是可以分配给字符的数字。UTF-8、UTF-16、UTF-32都是将数字转换到程序数据的编码方案。
通用字符集(Universal Character set,UCS)是由ISO制定的ISO 10646(或称ISO/IEC 10646)标准所定义的标准字符集。UCS-2用两个字节编码,UCS-4用4个字节编码。
实现方式
在Unicode中:汉字的“字”对应的数字是23383。在Unicode中,有许多方式将数字23383表示成程序中的数据,包括UTF-8、UTF-16、UTF-32。UTF是“UCS Transformation Format”的缩写,Unicode字符集转换格式,即怎样将Unicode定义的数字转换成程序数据。例如,“汉字”对应的数字是0x6c49和0x5b57,而编码的程序数据是:
BYTE date_utf8[]={0xE6,0xB1,0x89,0xE5,0xAD,0x97};
可见,一个汉字以UTF-8编码是占三个字节。
UTF-8
UTF-8以字节为单位对Unicode进行编码。从Unicode到UTF-8的编码方式如下:
Unicode编码(16进制) UTF-8字节流(二进制)
000000-00007F 0xxxxxxx
000080-0007FF 110xxxxx 10xxxxxx
000800-00FFFF 1110xxxx 10xxxxxx 10xxxxxx
010000-10FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
UTF-8的特点是对不同范围的字符使用不同长度的编码,所以UTF-8兼容ASCII编码。UTF-8编码的最大长度是4个字节。从上表可以看出,4个字模板有21个x,即可以容纳21位二进制数字。Unicode的最大码位0x10FFFF也只有21位。
从Unicode编码的UTF-8实现方式比较好理解:
例如,汉字的“汉”字的Unicode编码是0x6C49。0x6C49是在0x800-0xFFFF之间,则对应用UTF-8来实现需要点三个字节,1110xxxx 10xxxxxx 10xxxxxx。
0x6C49的二进制是0110 1100 0100 1001,用这个比特流依次代替模板中的x,即用0110 1100 0100 1001从低位到高位替代1110xxxx 10xxxxxx 10xxxxxx的x位,不足时用0代替。
0110 1100 0100 1001
1110xxxx 10xxxxxx 10xxxxxx
11100110 10110001 10001001
现在谈谈针对是UTF-8编码方式而言退格键的实现。
void utf8_backspace(char *text) {int n = strlen(text);char *last_byte = text + n - 1;if(!((*last_byte) & 0x80)) {text[n-1] = '\0';} else if(((*(last_byte-1)) & 0xc0) == 0xc0) {text[n-2] = '\0';text[n-1] = '\0';}else if(((*(last_byte-2)) & 0xe0) == 0xe0) {text[n-3] = '\0';text[n-2] = '\0';text[n-1] = '\0';} else if(((*(last_byte-3)) & 0xf0) == 0xf0) {text[n-4] = '\0';text[n-3] = '\0';text[n-2] = '\0';text[n-1] = '\0';} else{ printf("[%s]:%d,uft8 backspace error\n",_FILE_,_LINE_);} }
UTF-8理论上最多可以是6个字节,这里只考虑4个字节,因为大部分4个字节就已经足够。
这个实现退格键的前提是你的字符是经过UTF-8,如果是其它的,如GB2312等须先进行编码转换成UTF-8才能用。
Unicode能显示20901个汉字,范围是从\u4e00到\u9fa5,下面程序是输出Unicode编码下的所有汉字。
//C# codechar minHZUnicode = '\u4e00'; char maxHZUnicode = '\u9fa5';for (char c = minHZUnicode; c <= maxHZUnicode; c++) {Console.Write(c); }
由谈退格键的实现来学习字符编码相关推荐
- 解决ubuntu20.04下vi编辑器方向键和退格键问题
在ubuntu中,进入vi命令的插入模式,发现方向键分别对应ABCD以及退格键失效,按方向键不能移动光标,而是会输出ABCD,以及退格键也不能正常删除字符,我们这里提供两种解决方法 方法一 1.先卸载 ...
- ubuntu18.04下vi不能使用方向键和退格键
方法1 使用vi命令时,不能正常编辑文件,使用方向键时老是出现很多字母? 在Ubuntu中,进入vi命令的编辑模式,发现按方向键不能移动光标,而是会输出ABCD,以及退格键也不能正常删除字符.这是由于 ...
- 解决Ubuntu中vi命令的编辑模式下不能正常使用方向键和退格键的问题
在Ubuntu中,进入vi命令的编辑模式,发现按方向键不能移动光标,而是会输出ABCD,以及退格键也不能正常删除字符.这是由于Ubuntu预装的是vim-tiny,而我们需要使用vim-full,解决 ...
- python使用退格键时出现^H解决方法
python使用退格键时出现^H解决方法 参考文章: (1)python使用退格键时出现^H解决方法 (2)https://www.cnblogs.com/effortsing/p/9982040.h ...
- 屏蔽鼠标右键、Ctrl+N、Shift+F10、F11、F5刷新、退格键
<script language="Javascript"><!-- //屏蔽鼠标右键.Ctrl+N.Shift+F10.F11.F5刷新.退格键 //A ...
- Linux下使用Vi是方向键变乱码 退格键不能使用的解决方法
在Linux下编辑一些文件.这就涉及到了vi这个编辑器了.在Linux下,初始使用vi的时候有点问题.就是在编辑模式下使用方向键的时候,并不会使光标移动,而是在命令行中出现[A [B [C [D之类的 ...
- 解决ubuntu中vi不能正常使用方向键与退格键的问题
解决ubuntu中vi不能正常使用方向键与退格键的问题 方案一: 问题: ubuntu中vi在编辑状态下方向键不能用,还有回格键不能删除等我们平时习惯的一些键都不能使用. 解决办法: 可以安装vim ...
- linux 使用退格键时出现^H解决方法
个人博客迁移 更多内容分享请访问 http://www.wpython.com 当我们再和脚本交互的时候 在终端上输错了内容 使用退格键 屏幕上会出现乱码 比如 ^H ^H不是H键的意思,是bac ...
- 树莓派vi编辑文件时退格键和方向键无法正常使用的问题
[问题现象] 树莓派在使用vi编辑文件时,发现退格删除键(Backspace键),无法删除,方向键变成了ABCD(对应上下右左)还自动换行. 现象如下图所示: [问题解决] 此问题根因是树莓派系统预装 ...
最新文章
- 杨强 : 迁移学习——人工智能的最后一公里
- 白话Elasticsearch68-ES生产集群部署重要的操作系统设置
- html5内容切换特效,html5+jQuery图片和文字内容同时左右切换特效
- Android(java)学习笔记133:Eclipse中的控制台不停报错Can't bind to local 8700 for debugger...
- 测试次数----2018年第九届蓝桥杯C/C++省赛B组 第四题
- PyCharm 配置 Git 教程
- 基于 Direct3D 电子海图区域绘制方法
- dllMain函数的作用
- 列举在100到200以内的质数
- mysql生成数据字典
- 数字鉴相,关于相位差的提取
- 【笔记】用Python写百度翻译网络爬虫
- python转义字符:‘\‘
- HttpClient发送请求时动态替换目标ip
- rss 是什么?有什么用?
- python爬取微信好友头像_python 使用wxpy实现获取微信好友列表 头像 群成员
- 黑群晖 无法关机_教你无U盘引导实现黑群晖6.1.3 15152,打造属于自己的私人云空间...
- HTTP请求服务器 statuscode的状态码说明 (statuscode==500)
- 原神改文件换服务器,原神B服怎么转成官服
- [@vue/compiler-sfc] defineProps is a compiler macro and no longer needs to be imported
热门文章
- 领结婚证了,新的人生开始了!
- C++ delete 和 delete []的区别
- day002-HTML知识点总结:浏览器兼容性之指定IE浏览器使用chrome内核渲染页面
- 2016/09/14
- 2016.5.27 科学————量子力学初识
- 几个SQL命令的使用
- 对gridview中的一些操作。
- 学习 TTreeView [15] - 连接数据库 (作为给 丁永其 和 DELPHI万岁 两位朋友的回复)...
- VirtualBox安装kali linux过程及安装后无法全屏问题解决方法(2)
- 同一DIV内,两个行内块元素不对齐的解决方案