Go-字符串编码Unicode-和UTF8

1.字符串字符串在Go语言中以原生数据类型出现,使用字符串就像使用其他原生数据类型(int、bool、 float32、foat64等)一样。 字符串的值为双引号中的内容,可以在Go语言的源码中直接添加非ASCⅡ码字符 Go语言的字符串常见转义符包含回车、换行、单双引号、制表符等,如下所示 转移符 含义 \r 回车符(返回行首)\n 换行符(直接跳到下一行的同列位置)\t 制表符\' 单引号\" 双引号\\ 反斜杠2.字符串实现基于UTF-8编码 go 语言里的字符串的内部实现使用UTF8编码. 通过rune类型,可以方便地对每个UTF-8字符进行访问。 当然,Go语言也支持按传统的ASCII码方式进行逐字符访问。 3.字符 字符串中的每一个元素叫做“字符”,在遍历或者单个获取字符非元素时可以获得字符。 Go语言的字符有以下两种: 一种是uint8类型,或者叫byte型,代表了ASCII码的一个字符。另一种是rune类型,代表一个UTF-8字符。当需要处理中文、日文或者其他复合字符时,则需要用到rune类型。rune类型实际是一个int32。使用 fmt.Printf中的“%T”动词可以输出变量的实际类型,使用这个方法可以查看byte和rune的本来类型,代码如下: var a byte = 'a'fmt.Printf("%d %T\n", a, a)var b rune='你'fmt.Printf("%d %T\n", b, b)输出如下97 uint820320 int324.UTF-8和 Unicode有何区别? Unicode是字符集。ASCⅡ也是一种字符集。 字符集为每个字符分配一个唯一的ID,我们使用到的所有字符在 Unicode字符集中都有唯一的一个ID对应,例如上面例子中的a在 Unicode与ASCII中的编码都是97。 “你“在 Unicode中的编码为20320,但是在不同国家的字符集中,“你”的ID会不同。而无论任何情况下, Unicode中的字符的ID都是不会变化的。 UTF-8是编码规则,将 Unicode中字符的ID以某种方式进行编码。UTF-8的是一种变长编码规则,从1到4个字节不等。 5.计算字符串长度 tip := "genji is a ninja"fmt.Println(len(tip))tip2 := "认真"fmt.Println(len(tip2))结果:166len 表示字符串的ASCII 字符个数或字节长度 所以:ASCII 字符串长度使用len() 长度Unicode 字符串长度使用utf8.RuneCountInString() 5.字符串遍历1.遍历每一个 ASCII 字符直接使用for 2.按Unicode 字符遍历字符串使用 range ...

June 1, 2019 · 1 min · jiezi

字符编码那些事儿

身为一名要冲出国门的国际化码农????,字符编码是必备课题。小拽本文依次介绍下字节,ASCII,GB2312,GBK,GB18030,UNICODE,UTF8,UTF16,ICU 等到底是什么鬼?最后理论结合实际,研究下网站中经常出现的“锟斤拷,��,烫烫烫烫烫,屯屯屯屯屯屯”是什么神兵利器O(∩_∩)O?一、二进制和字节大概一百多年前,贝尔实验室制造了世界上的第一个晶体管,晶体管具有开合(0和1)的状态,这种01状态的变化被称为二进制位(bit)。 过了几年,英特尔把八个可以开合的晶体管组合,做为一个基本的记录单元,这个单元被称作字节(byte),所以一个byte由8个bit构成,可以表达256种状态。 又过几年,祖师爷冯诺依曼设计了一台可以存储和处理(冯诺依曼体系)字节变动的机器ENIAC,后来这个机器被称作计算机。 二、标准ASCII计算机运行是二进制,如何用二进制位来标识人类语言,就需要和计算机有一套约定关系。例如约定,0100 1111代表O,0100 1011代表K,那么存储为01001111 01001011的两个字节就代表OK,这套约定关系被称作字符编码。 冯祖师爷是的德国人,二战去了美国设计了第一台计算机。起初,只有美国人能用计算机,山姆大叔就根据英语习惯设计了一套映射约定 0-31 标识控制字符,例如换行[LF],删除[DEL],确认[ACK]等32-47 标识符号例如!@#$等48-57 标识0-9是个阿拉伯数字65-122 标识大小写字母大家都按着这个约定来,交流表达起来没啥问题,呵呵,都挺好。于是这个方案就一致通过了,山姆大叔也给这个约定起了个名字ASCII编码(American Standard Code for Information Interchange,美国信息互换标准代码)。当时世界上所有的计算机都用同样的ASCII方案来保存英文字符。 计算机一个标准字节8bit本身可以标识256个符号,但标准的ASCII的最高位去掉用做奇偶校验,用剩余7位标识128个符号,如下图 三、ASCII 扩展字符集随着计算机的发展,欧洲人开始逐步接触计算机了。 英语用128个符号编码就够了,但是用来表示其他语言,128个符号是不够的。比如在法语中,字母上方有注音符号,它就无法用ASCII码表示。于是,一些欧洲国家就决定,利用字节中闲置的最高位编入新的符号。比如,法语中的é的编码为130(二进制10000010)。这样一来,这些欧洲国家使用的编码体系,可以表示最多256个符号。 IBM牵头扩充了ASCII编码128-256位的标识字符,主要是一些欧洲的常用符号,这部分扩展映射被称为ASCII扩展字符集 四、GB2312雄关漫道真如铁,而今迈步从头越,美帝国主义万万没有想到,二战后,大量第三世界的人民站起来了,逐步开始使用计算机。但问题是256个字符已经没啥可利用的字节状态来表示汉字了,更何况中华文明有6000多个常用汉字需要保存呢。 但是这难不倒智慧的中国人民,面对帝国主义的压迫,我们毫不客气的做了两件事情,并在1980年发表了这个声明 互相尊重:尊重标准ASCII 规范中0-127位表示的标准字符。平等互利:ASCII的128-256位,我们用来标识中文,由于中文太多,我们要使用两个字节来表示一个中文^_^中国人民觉的这个声明还不错,毕竟当时计算机的使用范围也不大,基本满足需求,于是就把这种汉字方案叫做 GB2312编码。GB2312 是对 ASCII 的中文扩展。 非专业人士可以忽略: GB2312如何组合,能表示多少个?GB2312中用两个字节来标识一个汉字,前面的一个字节(他称之为高字节)从0xA1用到0xF7,后面一个字节(低字节)从0xA1到0xFE,简单计算0xA1:10*16 + 1 = 161 0xF7:15*16 + 7 = 247 => 247-161 = 860xFE:15*16 + 14= 254 => 254-161 = 93因此GB2312可以标识约86*93=7998 个汉字实时上 GB2312 标准共收录 6763 个汉字,其中一级汉字 3755 个,二级汉字 3008 个。同时收录了包括拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母在内的 682 个字符。几乎覆盖了大陆常用的99.75%汉字这样我们就可以组合出大约7000多个简体汉字了。在这些编码里,我们还把数学符号、罗马希腊的字母、日文的假名们都编进去了,连在 ASCII 里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的全角字符,而原来在127号以下的那些就叫半角字符了。 ...

May 12, 2019 · 2 min · jiezi

webSocket 二进制传输基础准备-UTF16 转UTF8

前言今天学习一下编码,先回顾一下昨天的基础准备工作。下面进行了解UTF-8与UTF-16的二进制编码方式。为啥要了解这个,因为js中所有是string类型都是使用UTF-16编码的因此我们与后端进行通信时,需要转换成与之一致的编码。(后端或者前端转换)UTF-8编码方式注: 1. Unicode码范围 用十六进制表示 3. 8位二进制为一字节Unicode码范围UTF-8编码方式占用字节U+0000 ~ U+007F0xxxxxxx1U+0080 ~ U+ 07FF110xxxxx 10xxxxxx2U+0800 ~ U+FFFF1110xxxx 10xxxxxx 10xxxxxx3U+10000 ~ U+10FFFF11110xxx 10xxxxxxx 10xxxxxx 10xxxxxx4Unicode码转换UTF-8Unicode编码表使用,转换到UTF-8编码在Unicode中汉字 “一”编码为U+4E00,“丁"编码为 U+4E01这样想必就看得懂表了下面进行开始转换吧回顾昨日的二进制与十六进制U+4E00用十六进制表示 0x4E00转换二进制,按位转换4 = 0011E = 14 = 11100 = 00000 = 00000x4E00 = 0100 1110 0000 0000 = 199680x0800< 0x4E00 < 0xFFFF 得出是三个字节。UTF-8三字节的编码方式从 0100 1110 0000 0000 变成 1110 xxxx 10 xxxxxx 10 xxxxxx格式由从末位到首位进行顺位插入的方式 0100 111000 0000001110 xxxx 10 xxxxxx 10 xxxxxx1110 0100 10 111000 10 000000其中利用js的按位操作符 符号操作符进行转换先替换原码(从末位到首位)的第7位8位第一字节utf-8 3字节中的第一字节格式 为 10 xxxxxx所有截取6位(原码与编码对应的 为x的位值,要保持不变, 编码其中的x位值全部为原码)先利用按位与的特性(全1为1 否则为0)进行截取原码的末6位二进制 111111 = 63十进制0100 1110 0000 0000 & 0000 0000 0011 1111 = 00000019968 & 63 = 000000UTF-8的第一字节格式为 10 xxxxxx所以利用按位或的特性(遇1为1,全0 为0)来变换UTF-8 3字节中的第一个字节的编码方式将x替代为0 得出 10 000000二进制 10 000000 = 128;按位或00 000000 | 10 000000 = 10 0000000 | 128 = 128第二个字节UTF-8 3字节中的第二字节依然是10 xxxxxx格式,所以只需要从第6位开始进行截取6位利用带符号右移操作符 a >> b 首位开始补 b 个 首位值 右侧舍去b个位先舍去末6位0100 1110 0000 0000 >> 6 = 000 000 0100 1110 0019968 >> 6 = 312利用按位与进行截取000 000 0100 1110 00 & 111111 = 111 000312 & 63 = 56继续利用按位或进行变换00 111000 | 10 000000 = 10 11100056 | 128 = 184第三字节utf-8 3字节的第三字节编码方式为 1110 xxxx 所以只需要从第12开始截取4位从末位第12位开始截取4位,利用带符号右移操作符 a >> b 首位开始补 b 个 首位值 右侧舍去b个位0100 1110 0000 0000 >> 12 = 000 000 0000 010019968 >> 12 = 4利用按位与进行截取 4位二进制 1111 = 150100 & 1111 = 01004 & 15 = 4;利用按位或进行变换二进制 1110 0000 = 2240000 0100 | 1110 0000 = 1110 01004 | 224 = 228三个字节组合起来228 184 128 = 1110 0100 1011 1000 1000 0000(二进制) = 14 4 11 8 8 0( 四位转一位十进制) =0xe4b880(十六进制)utf-16转utf-80x4E00 = 0xe4b880python编码转换b’\xe4\xb8\x80’.decode(‘utf-8’) = “一” ...

April 3, 2019 · 2 min · jiezi

MySQL乱码的原因和设置UTF8数据格式

MySQL使用时,有一件很痛苦的事情肯定是结果乱码。将编码格式都设置为UTF8可以解决这个问题,我们今天来说下为什么要这么设置,以及怎么设置。MySQL字符格式字符集在编程语言中,我们为了防止中文乱码,会使用unicode对中文字符做处理,而为了降低网络带宽和节省存储空间,我们使用UTF8进行编码。对这两者有什么不同不够了解的同学,可以参考Unicode字符集和UTF8编码编码的前世今生这篇文章。同样在MySQL中,我们也会有这样的处理,我们可以查看当前数据库设置的编码方式(字符集):mysql> show variables like ‘%char%’;+————————–+———————————-+| Variable_name | Value |+————————–+———————————-+| character_set_client | latin1 | | character_set_connection | latin1 | | character_set_database | latin1 | | character_set_filesystem | binary | | character_set_results | latin1 | | character_set_server | latin1 | | character_set_system | utf8 | | character_sets_dir | /usr/local/mysql/share/charsets/ | +————————–+———————————-+8 rows in set (0.00 sec)表中就是当前设置的字符集,先看不用关注的几个值:character_set_filesystem | binary:文件系统上的存储格式,默认为binary(二进制)character_set_system | utf8:系统的存储格式,默认为utf8character_sets_dir | /usr/local/mysql/share/charsets/:可以使用的字符集的文件路径剩下的几个就是日常影响读写乱码的参数了:- character_set_client:客户端请求数据的字符集- character_set_connection:从客户端接收到数据,然后传输的字符集- character_set_database:默认数据库的字符集;如果没有默认数据库,使用character_set_server字段- character_set_results:结果集的字符集- character_set_server:数据库服务器的默认字符集字符集的转换流程分为3步:客户端请求数据库数据,发送的数据使用character_set_client字符集MySQL实例收到客户端发送的数据后,将其转换为character_set_connection字符集进行内部操作时,将数据字符集转换为内部操作字符集:使用每个数据字段的character set设定值若不存在,使用对应数据表的default character set设定值若不存在,使用对应数据库的default character set设定值若不存在,使用character_set_server设定值将操作结果值从内部操作字符集转换为character_set_results字符序说字符序之前,我们需要了解一点基础知识:字符(Character)是指人类语言中最小的表义符号。例如’A’、’B’等;给定一系列字符,对每个字符赋予一个数值,用数值来代表对应的字符,这一数值就是字符的编码(Encoding)。例如,我们给字符’A’赋予数值0,给字符’B’赋予数值1,则0就是字符’A’的编码;给定一系列字符并赋予对应的编码后,所有这些字符和编码对组成的集合就是字符集(Character Set)。例如,给定字符列表为{‘A’,’B’}时,{‘A’=>0, ‘B’=>1}就是一个字符集;字符序(Collation)是指在同一字符集内字符之间的比较规则;确定字符序后,才能在一个字符集上定义什么是等价的字符,以及字符之间的大小关系;每个字符序唯一对应一种字符集,但一个字符集可以对应多种字符序,其中有一个是默认字符序(Default Collation);MySQL中的字符序名称遵从命名惯例:以字符序对应的字符集名称开头;以_ci(表示大小写不敏感,case insensitive)、_cs(表示大小写敏感,case sensitive)或_bin(表示按编码值比较,binary)结尾。例如:在字符序“utf8_general_ci”下,字符“a”和“A”是等价的;因此字符序不同于字符集,用于数据库字段的相等或大小比较。我们查看MySQL实例设置的字符序:mysql> show variables like ‘collation%’;+———————-+——————-+| Variable_name | Value |+———————-+——————-+| collation_connection | latin1_swedish_ci | | collation_database | latin1_swedish_ci | | collation_server | latin1_swedish_ci | +———————-+——————-+3 rows in set (0.00 sec)跟utf8对应的常用字符序是:utf8_unicode_ci/utf8_general_ci和utf8_bin等,那么他们的区别是什么呢?_bin是用二进制存储并比较,区别大小写,存储二进制内容时使用utf8_general_ci:校对速度快,但准确度稍差,使用中英文时使用utf8_unicode_ci:准确度高,但校对速度稍慢,使用德法俄等外语时使用详细的区别可以参考 Mysql中的排序规则utf8_unicode_ci、utf8_general_ci的区别总结。修改字符集和字符序如果在MySQL连接时,出现了乱码的问题,那么基本可以确定是各个字符集/序设置不统一的原因。MySQL默认的latin1格式不支持中文,由于我们在中国,所以选择对中文和各语言支持都非常完善的utf8格式。所以,我们需要将需要关注的字符集和字符序都修改为utf8格式。你也可以选择utf8mb4格式,这个格式支持保存emoji????表情。我们需要修改Mysql的配置文件,查看配置文件的位置有两种方式:1. $ mysql –help | grep ‘my.cnf’ /etc/mysql/my.cnf /etc/my.cnf ~/.my.cnf 2. ps aux | grep mysql在(1)中,/etc/my.cnf, /etc/mysql/my.cnf, ~/.my.cnf 这些就是mysql默认会搜寻my.cnf的目录,优先级依次升高。可以在各个配置文件里都使用long_query_time 来测试一下。然后,我们修改或新增下面的配置项:# 下面注释的几行可以不设置,但如果你的没有生效,也可以试试看[mysqld]character_set_server=utf8collation-server=utf8_general_ciskip-character-set-client-handshake#init_connect=‘SET NAMES utf8’#[client]#default-character-set=utf8这三行配置就可以解决问题,最关键的是最后一行,参考mysql文档,使用该参数会忽略客户端传递的字符集信息,而直接使用服务端的设定;再加上我们设定服务端的字符集和字符序均为utf8,这样就保证了字符格式的统一,解决乱码的问题。重启mysql服务,如果提示找不到服务,请参考用service命令管理mysql启停:$ service mysqld restartShutting down MySQL.. [ OK ]Starting MySQL. [ OK ]连接到mysql,查看当前编码:mysql> show variables like ‘%char%’;+————————–+———————————-+| Variable_name | Value |+————————–+———————————-+| character_set_client | utf8 | | character_set_connection | utf8 | | character_set_database | utf8 | | character_set_filesystem | binary | | character_set_results | utf8 | | character_set_server | utf8 | | character_set_system | utf8 | | character_sets_dir | /usr/local/mysql/share/charsets/ | +————————–+———————————-+8 rows in set (0.01 sec)mysql> show variables like ‘collation%’;+———————-+—————–+| Variable_name | Value |+———————-+—————–+| collation_connection | utf8_general_ci | | collation_database | utf8_general_ci | | collation_server | utf8_general_ci | +———————-+—————–+3 rows in set (0.01 sec)可以看到一切都符合预期,请求和存储的数据也不再是乱码了。遇到的问题unknown variable ‘default-character-set=utf8’参考官方文档,该参数自5.5.3版本废弃,改为了character-set-server,改为这个参数即可。但这个是在[mysqld]下的配置,在[client]下的配置依然使用default-character-set参数。参考资料MySQL连接校对:utf8_general_ci与utf8_unicode_ci有什么区别呢 :https://segmentfault.com/q/10…Unicode 和 UTF-8 有什么区别?:https://www.zhihu.com/questio…深入Mysql字符集设置:http://www.laruence.com/2008/…10.4 Connection Character Sets and Collations:https://dev.mysql.com/doc/ref…ISO/IEC 8859-1:https://zh.wikipedia.org/wiki…5.1.6 Server Command Options:https://dev.mysql.com/doc/ref…用service命令管理mysql启停:https://segmentfault.com/a/11…Unicode字符集和UTF8编码编码的前世今生:https://segmentfault.com/a/11…Mysql中的排序规则utf8_unicode_ci、utf8_general_ci的区别总结:https://www.jb51.net/article/… ...

March 26, 2019 · 2 min · jiezi

关于字符编码你应该知道的事情

读完本文你将了解的知识点为什么 Windows 上使用 Notepad 会出现乱码为什么 Emoji 表情在有些手机上显示不准确为什么 Emoji 在没有做过特殊优化的数据库中存储失败为什么使用 Linux 开发的代码他人使用 Windows 开发后换行符全变了为什么在 JS 中 […’????????????????’] => ["????", “”, “????”, “”, “????”, “”, “????"]新版本 ECMAScript 针对 JavaScript 编码问题做了哪些改进为什么使用 Google Chrome 打开 JS 文件,文件中的中文字符会变成乱码比特、字节比特 ( Bit / Binary digit )缩写为 b,计算机最小的存储单位,以 0/1 来表示值字节 ( Byte )缩写为 B,8 个比特表示一个字节在计算机内部,所有的信息最终都表示为一个二进制的序列。每一个二进制位 ( Bit ) 有 0 和 1 两种状态,因此八个二进制位就可以组合出 256 种状态,这被称为一个字节 ( Byte ) ,也就是说,一个字节一共可以用来表示 256 种不同的状态或者符号。如果我们制作一张对应表格,对于每一个 8 位二进制序列,都对应唯一的一个符号。每一个状态对应一个符号,就是 256 个符号,从 0000 0000 到 1111 1111 。ASCII 与 EASCIIASCII (American Standard Code for Information Interchange,美国信息交换标准代码)1967 年发布,最后更新于 1986 年,共定义了 128 ( 2 ) 个字符( 0x00 - 0x7F ) ,其中 33 个字符为不可打印字符 ( 0x00 - 0x1F & 0x7F ),95 个可打印字符 ( 0x20 - 0x7E )可打印字符为标准键盘中可输入的字符,如下所示:10 个数字 ( 0-9 ),26×2 个大小写字母 ( a-z A-Z ) ,32 个标点符号 1 个空格 ( ,./;’[]-=!@#$%^&*()_+{}|:"<>? )ASCII 的局限在于只能显示 26 个基本拉丁字母、阿拉伯数目字和英式标点符号,因此只能用于显示现代美国英语,而其他携带类似于重音符号的字母无法显示 ( naïve、café )EASCII ( Extended ASCII,延伸美国标准信息交换码 )由于 ASCII 的天然不足,它的变种体迅速出现,兼容字符集对ASCII的处理ISO/IEC 646 1972年该标准来自数个国家标准,最主要的是美国的 ASCII 标准,ISO 646 为了表示欧洲各种语言的带附加符号( diacritical mark )的变音字母,由于没有码位空间去直接编码这些变音字母,所以用几个标点符号来兼作变音字母的附加符号ISO/IEC 8859扩展字符:0xA0 ( 160 ) - 0xFF ( 255 ) 淘汰了 ISO 646 编码标准 ISO 8859 统一了此前各国各语言的单独编码的混乱局面;废弃了 ISO 646 使用的退格键开始的转义序列来表示变音字母的方法,而是在 G1 区域直接编码表示变音字母。ISO 8859 有 15 个子版本( 1-11,13-16 ),其中囊括了大部分欧州语言,英语因为没有重音字母,所有可以使用其中任何一个子版本表示Microsoft Codepage 1252 为 ISO 8859-1 的超集,扩充了 0x80 - 0x9F 来编码一些可打印字符 ( ‚ ƒ „ … † ‡ ‰ Š ‹ Œ Ž ‘ ’ “ ” • – — ™ š › œ ž Ÿ )例如在中国 GB/T 1988-80 标准中: $ u+0024 替换为 ¥ u+00A5 , u+007E 替换为 ‾ u+203EANSIWindows 操作系统上的 ANSI 编码并不是指的是美国国家标准学会 ( ANSI ),而是用来指称多个不同的代码页,比如在简体中文编码操作系统中,ANSI 实际使用 GB 系字符编码中文GB2312 ( 1981 ) 6763 个汉字,最初版本,双字节编码GB12345 ( 1993 ) 6866 个汉字,为了适应繁体汉字信息处理而制定的标准GBK ( 1995 ) 21886个汉字和图形符号,不属于国家标准GB18030 ( 2000 ),70244 个字符,基于 GBK,现行版本国际通用标准Unicode ( 万国码、国际码、统一码、单一码 )最初版本:1.0.0 发布,1991 年 10 月发布,7161 个字符当前正式版本 Unicode 11.0 ( 2018 年 6 月 ) 拥有 137374 个字符当前最新版本:Emoji 12.0 Beta表示方法:基本平面:通常会用 “U+” 然后紧接着 4 个 16 进制的数字来表示这一个字,可表示 6 万余个字符其他平面使用 “U-” 然后接着 8 个 16 进制数字表示ISO/IEC 10646 ( UCS / 通用字符集 )该字符集包括了其他所有字符集,保证了与其他字符集的双向兼容,ISO 10646 有三种实现级别,不同的实现级别能支持的字符数量不同与 Unicode 的关系:所有字符在相同位置且有相同名字Unicode 标准里有详细说明某些语言和文字的表达算法等ISO 承诺,ISO 10646 将不会替超出 U+10FFFF( Unicode 编码以 U+ 开头) 的 UCS-4 编码赋值UTF ( Unicode Transformation Format )Unicode 是一个字符集,其实现方式称为 Unicode 转换格式,即 UTFUTF-32Unicode 与 UCS 合并之前已经产生了 UCS-4 编码方式,UCS-4 使用了 32 位来表示每个编码,为了兼容 Unicode 产生了 UTF-32 标准,编码空间限制在了 0x000000 - 0x10FFFF 之间,因此可以说 UTF-32 是 UCS-4 的子集。由于 UTF-32 的编码空间占用过大,因此在 HTML5 标准中明确规定不能使用 UTF-32 进行编码UTF-16UTF-16 编码拥有定长和变长两个编码特点,对于 Unicode 基本平面的字符,UTF-16 占用两个字节,对于辅助平面的字符,UTF-16 编码占用四个字节Unicode 规范定义,每一个文件的最前面分别加入一个表示编码顺序的字符,这个字符的名字叫做 “零宽度非换行空格 ( zero width no-break space )”,用 FE FF 表示。但在不同计算机系统中对字节顺序的理解是不一致的,即出现了大端序 ( UTF-16 BE ) 与小端序 ( UTF-16 LE ) 两种情况。文本头部使用 FE FF 与 FF FE 进行区分,此区分符称为“字节顺序标记 ( BOM ) ”如何确定双字节和四字节:在基本平面内,从 U+D800 到 U+DFFF 是一个空段,不对应任何码点,这个空段用来映射辅助平面的字符,即一个辅助平面的字符,被拆成两个基本平面的字符表示。例如: ???? 可以表示为 U+D83D U+DC68UTF-8由于前两种编码方式的编码规则对与英语国家来说非常浪费(2-4 字节编码)UTF-8 当前使用 1-6 个字节为每个字符编码对于单字节的符号,字节的第一位设为 0 ,后面 7 位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。对于n字节的符号( n > 1 ),第一个字节的前n位都设为 1,第 n + 1 位设为0,后面字节的前两位一律设为 10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。带有附加符号的拉丁文、希腊文、西里尔字母、亚美尼亚语、希伯来文、阿拉伯文、叙利亚文及它拿字母则需要两个字节编码 ( Unicode 范围由 U+0080 至 U+07FF )。其他基本多文种平面 ( BMP ) 中的字符(这包含了大部分常用字,如大部分的汉字)使用三个字节编码 ( Unicode范围由U+0800至U+FFFF )。其他极少使用的 Unicode 辅助平面的字符使用 4-6 字节编码UCS-2JavaScript 采用了 Unicode 字符集。但是只支持一种编码方式。JS 最先采用的编码既不是 UTF-16 也不是 UTF-32 或 UTF-8 ,而是 UCS-2 。UTF-16 明确宣布是 UCS-2 的超集。UTF-16 中基本平面字符延用 UCS-2 编码。辅助平面字符定义了 4 个字节的表示方法。JS 只能处理 UCS-2 编码,造成所有字符在这门语言中都是两个字节,如果是四个字节的字符。会被当做两个双字节的字符处理。两者的关系简单说,就是 UTF-16 取代了 UCS-2,或者说 UCS-2 整合进了 UTF-16。所以,现在只有 UTF-16,没有 UCS-2。码点和平面字符会从 0 开始为每个字符指定一个编码, 这个编码叫做码点举例Unicode 中给字符进行分区定义,每个区称为一个面,Unicode 拥有 0-16 共 17 个平面,每个平面 16 个字符平面字符值描述0号平面U+0000 - U+FFFF基本多文种平面1号平面U+10000 - U+1FFFF多文种补充平面2号平面U+20000 - U+2FFFF表意文字补充平面3号平面U+30000 - U+3FFFF表意文字第三平面(未正式使用)4 - 13号平面U+40000 - U+DFFFF(尚未使用)14号平面U+E0000 - U+EFFFF特别用途补充平面15号平面U+F0000 - U+FFFFF保留作为私人使用区(A区)16号平面U+100000 - U+10FFFF保留作为私人使用区(B区)题首问题为什么 Windows 上使用 Notepad 会出现乱码Windows 上的 Notepad 软件在保存文件时默认使用的是 ANSI 编码保存,而在打开的时候需要猜测 txt 文件的编码方式,如果文档中出现了 ANSI 编码以外的字符,则在打开时候可能会出现编码识别错误的情况,由于 txt 文件为纯文本文件,没有保存文档编码信息的区域,则此问题可能一直存在。解决该问题可在保存文件的时候使用 UTF-8 编码保存,但需要注意的是:Windows 的 Notepad 应用使用 UTF-8 保存的时候实际使用的为 UTF-8 BOM 方式,其表现为在文本最开头添加 EF BB BF ,这部分称为 UTF-8 字节顺序标记 ,该方式并非强制标准,如果在代码文件中使用该方式保存则有可能出现运行错误。为什么 Emoji 表情在有些手机上显示不准确当前 iOS 12 使用的 Unicode 版本为 11,而大众使用比较的 Android 8.0 使用的Unicode 版本为 9,如果在 Android 系统中出现了新版本的字符,则会出现无法显示或显示错误的情况。例如在 Unicode 8.0 中加入了 5 个菲茨帕特里克修饰符,用来调节人形表情的肤色,如果在低于此版本的 Unicode 中显示的字符为两个字符,分别是颜色加人偶。另外 Unicode 新版本中使用 U+200D 零宽连字 ( ZWJ ) 将多个 Emoji 连起来,例如 ???????????????? => ????????????????为什么 Emoji 在没有做过特殊优化的数据库中存储失败Emoji 表情占用 4 个字节,但是 MySQL 数据库使用的 utf-8 默认编码最多只能存储 3 个字节 ( UTF-8 标准支持最长编码为 6 字节 ),就会导致存储不进去,在读取的时候读取不完整,导致乱码修复方法为:修改数据库字符集为 uft8mb4,如果数据库连接池中对字符集作出了设置需要在链接中去掉 characterEncoding 参数为什么使用 Linux 开发的代码他人使用 Windows 开发后换行符全变了Windows 系列系统使用的换行标志为 CRLF,该换行标志与 Unix/Linux 的 LF 换行及 macOS 的 CR 换行不相同。如果在代码工程中使用了 Code Lint 工具自动格式化,可能会使代码中的 LF 换行自动转换为 CRLF 换行,Git 中也能捕获或忽略这个变化。另外,从 Windows 10 1803 开始,支持 Unix/Linux 的 LF 换行及 macOS 的 CR 换行。为什么在 JS 中 […’????????????????’] => [”????", “”, “????”, “”, “????”, “”, “????”]???????????????? 是 2015 年添加到 Emoji 2.0 中的新字符,使用 U+200D 零宽连字 (ZWJ) 将4个 Emoji 连起来,可使用以下代码检测[…’????????????????’].forEach(e=>{console.log(e.codePointAt().toString(16))})新版本 ECMAScript 针对 JavaScript 编码问题做了哪些改进由于 JavaScript 使用的是只支持双字节编码的 USC-2 编码方式,所以所有超过二字节编码的 Unicode 字符都无法在 JavaScript 中处理例如 ‘????’.charCodeAt().toString(16) 输出的结果为 d83d ,而????的Unicode 码点却不是 d83d,造成这样的原因为 JavaScript 只处理了该字符的前两个字节为了解决这些问题,ECMAScript 6 种增强了对新版本 Unicode 的支持。例如:for of 循环中对双字节以上字符能识别正确长度Array.from 等方法能正确划分字符串支持直接使用码点表示字符,例如’\ud83d\udc68’ === ‘????’ === ‘\u{1F468}‘String.fromCodePoint() 和 String.prototype.codePointAt() 等方法代替 String.fromCharCode() 和String.prototype.charCodeAt() 等方法,以用于支持 UTF-16 编码字符正则表达式提供了 u 修饰符,对正则表达式添加4字节码点的支持提供了normalize方法,允许"Unicode正规化" ,例如:’\u01D1’.normalize() === ‘\u004F\u030C’.normalize() 为什么使用 Google Chrome 打开 JS 文件,文件中的中文字符会变成乱码由于 2017 年更新的某版本 Chrome 中,去除了对 JS 文件默认编码 UTF-8 的支持,使用了系统默认编码(例如中文操作系统使用 GB18030 )对 JS 文件的解码,所以导致 JS 文件中的中文字符变成乱码。解决方法有两种:在文件服务器中对返回头的 Content-Type 设置加上 charset=UTF-8浏览器中使用插件改变网页编码方式,例如使用 FEHelper 工具参考资料:WikiPediaUnicode与JavaScript详解 - ruanyifeng一个表情引发的思考 - JDC「记事本」程序的BUG? - 知乎解决Emoji存储MySQL乱码问题本文首发地址blog.shoyuf.top第二次在 segmentfault 上发文章,欢迎各位评论区中吐槽指正 ...

February 19, 2019 · 4 min · jiezi