一.unicode编码
Unicode(统一码、万国码、单一码)是计算机科学领域里的一项业界标准,包括字符集、编码方案等。Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。1990年开始研发,1994年正式公布。
编码范围:0x0000-0x10FFFF。
此范围被分成了17个平面,其中,平面0(0x0000-0xffff)是基本多文种平面,包含了英文字母,阿拉伯数字,以及时间常用的各国语言。平面1(0x10000-0x1ffff)是多文种补充平面,包含了各国语言的补充以及emoji等。平面2(0x20000-0x2ffff)表意文字补充平面,此整个平面专为CJK即中日韩汉字编码设计。平面14(0xe0000-0xeffff)特别用途补充平面,此平面目前编码很少。平面15和平面16(0xf0000-10ffff)私人使用区,即自定义编码平面。其它平面基本上未编码。这个平面划分在维基百科上一目了然,下面附有链接地址。
平面0的专用区和代理区是未编码的具体如下:
专用区:0xE000-0xF8FF,6400个码位
专用区是留给自定义编码用的。
代理区:0xD800-0xDFFF,2048个码位
代理区是为utf-16编码方案用的,下面会具体讲到。
emoji:1F600-1F64F,2600-26FF,...
汉字:4e00-9FFF,扩展区A:3400-4DBF,扩展区B-F:20000-2EBEF
例如:汉字‘润'-0x6da6,emoji‘’-0x1f606
二.unicode编码实现
UTF:Unicode Transformation Format,即Unicode字符集转换格式。Unicode有3种实现方式即:utf-8、 utf-16、utf-32
1、utf-8:以8比特位为一个单位,一个字符的表示最少一个单位即一个字节,最大4个单位即4个字节。具体用几个单位需要看字符在unicode字符集里的码位,具体参考下表。
Unicode编码(十六进制) UTF-8 字节流(二进制) 000000-00007F 0xxxxxxx 000080-0007FF 110xxxxx 10xxxxxx 000800-00FFFF 1110xxxx 10xxxxxx 10xxxxxx 010000-10FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 2、utf-16:以16比特位为一个单位,一个字符的表示要么用一个单位即2个字节,要么用2个单位即4个字节。Unicode编码小于0x10000就用一个单位表示,0x10000-0x10ffff就用2个单位表示。
a.U<0x10000,utf-16就对应编码本身的无符号整数
b. U>=0x10000,
7字口诀就是:一减,二转,三模板。
1).减:U'=U-0x10000
例:0x1f606-0x1000
2).转:把U'转换为20位二进制,yyyy yyyy yyxx xxxx xxxx
3).模板:1101 10yy yyyy yyyy 1101 11xx xxxx xxxx
可以算一下,1101 10yy yyyy yyyy的取值范围1101 1000 ?0000 0000 - 1101 1011 1111 1111即D800-DBFF, 1101 11xx xxxx xxxx的取值范围1101 1100 0000 0000 - 1101 1111 1111 1111
即DC00-DFFF。所以,D800-DFFF即是unicode专为utf-16设计的代理区,其中,D800-DBFF是高代理区,DC00-DFFF是低代理区。代理区共2048个码位,unicode设计为保留区,没有具体编码,只为代理用。
我们在上面了解到平面15和平面16(0xf0000-0x10ffff)是私人使用区,我们把这个区间的编码使用上面公式可以算出,0xf0000-0x10000=e0000即11100000000000000000?,放入模板,1101 1011 1000 0000(DB80) 1101 1100 0000 0000(DC00),0x10ffff-0x10000=0xfffff,即11111111111111111111?,放入模板,1101 1011 1111 1111(DBFF) 1101 1111 1111 1111(DFFF)。因为平面15和16专用区utf-16的高位代理实现范围是:DB80-DBFF,所以DB80-DBFF(D800-DBFF高位代理区的子区间)又称为高位专用代理区。
相反,utf-16编码求unicode
a.判断:非代理区,此字符对应U<0x10000
b.代理区
1).模板:1101 10yy yyyy yy yy 1101 11xx xxxx xxxx
2).转:把yyyy yyyy yyxx xxxx xxxx转换为十六进制U'
3).加:U=U'+0x10000
3、utf-32以32个比特位为一个单位,即4个字节。所有的unicode编码都可以直接表示了,而且码位远远用不完。实现很简单,但是由于大部分字符用两个字节足够,4个字节太浪费空间了,所以很少用。
4、utf-8和utf-16方案对比1000汉字,1000英文对比
新建一个文本文件,随便输入1000个常见(4e00-9FFF)汉字,发现有3KB的大小。因为windows记事本默认用utf-8编码,而一个汉字用utf-8表示需要用3个字节,所以1000字就大约是3KB。我们文本另存为utf-16格式,发现大小变为了2KB。这因为utf-16表示汉字只需要2个字节,1000个汉字大约2KB。如果把1000汉字换成1000个英文字母或阿拉伯数字,结果你会发现,用utf-8格式只有1KB,而utf-16仍然是2KB。这是因为,对于1个英文字母或1个阿拉伯数字utf-8用一个单位即1个字节就可以表示了,而utf-16也至少要用一个单位就是2个字节。这个对比可以帮助我们直观的理解记忆utf-8和utf-16的区别。
也正因为全世界大部分常用字符码位还是在0x100-0xffff这个范围,所以最佳方案还是utf-16。Java char的设计就是一个很好的说明。java char 2个字节,默认编码方式utf-16。当然如果是纯英文和阿拉伯数字的程序选用utf-8编码也是可以理解的。
5、字节序把文本文档另存为utf-16时发现,确切的格式是UTF-16LE或者UTF-16BE。
BE(Big Endian)大字节字节序、LE(Little Endian)小字节字节序
注意:字节的顺序,非比特位的顺序;单位内字节顺序,非全部字节顺序。仔细观察对比0x6da6和0x1f606这两个字符的utf-16和utf-32实现,下表例子,你会明白这句话意思。
Unicode编码 UTF-16LE UTF-16BE UTF32-LE UTF32-BE 0x6da6 a6 6d 6d a6 a6 6d 00 00 00 00 6d a6 0x1f606 3D D8 06 DE D8 3D DE 06 06 f6 01 00 00 01 f6 06utf-8一个单位一个字节,所以没有大小字节序的区分。
UTF编码 Byte Order Mark (BOM) UTF-8 without BOM 无 UTF-8 with BOM EF BB BF UTF-16LE FF FE UTF-16BE FE FF UTF-32LE FF FE 00 00 UTF-32BE 00 00 FE FF注:FEFF-ZWNBSP:Zero-Width No-Break Space零宽不断行空白
微软在自己的UTF-8格式的文本文件之前加上了EF BB BF三个字节,
windows上面的notepad等程序就是根据这三个字节来确定一个文本文件是ASCII的还是UTF-8的,
然而这个只是微软暗自作的标记, 其它平台上不一定会对UTF-8文本文件做这样的标记。
微软的一些软件会做这种检测,但有些软件不做这种检测, 而把它当作正常字符处理。(传说中的乱码问题)
三.实战,判断字符串里是否包含emoji
1、需求只要输入的内容包含空格、花椒表情、emoji表情或超过10个字符就不关联,否则字符个数变动就关联。
需求分解:输入的内容是否包含emoji
2、实现public?static?boolean?containsEmoji(String?str)?{ ????int?len?=?str.length(); ????for?(int?i?=?0;?i?<?len;?i++)?{ ????????int?codePoint?=?Character.codePointAt(str,?i); ????????if?(isEmojiCharacterByWiki(codePoint))?{ ????????????return?true; ????????} ????} ????return?false; }
/** ?*?是否是emoji编码 ?*?//Superscripts?and?Subscripts(?2070?-?209F?)上标及下标 ?*?//Currency?Symbols(?20A0?-?20CF?)外汇符号 ?*?//Combining?Diacritical?Marks?for?Symbols(?20D0?-?20FF?) ?*?//Letterlike?Symbols(?2100?-?214F?)字母式符号?℃?、? ?*?//Number?Forms(?2150?-?218F?)数字形式?????Ⅷ ?*?//Arrows(?2190?-?21FF?)箭头???→ ?*?//Mathematical?Operators(?2200?-?22FF?)数学操作符 ?*?//Miscellaneous?Technical(?2300?-?23FF?)零杂技术用符号 ?*?//Control?Pictures(?2400?-?243F?)控制图片 ?*?//Optical?Character?Recognition(?2440?-?245F?)光学字符辨识 ?*?//Enclosed?Alphanumerics(?2460?-?24FF?)封闭式字母数字 ?*?//Box?Drawing(?2500?-?257F?) ?*?//Box?Elements(?2580?-?259F?) ?*?//Geometric?Shapes(?21A0?-?21FF?)几何图形 ?*?//Miscellaneous?Symbols(?2600?-?26FF?)杂项符号 ?*?//Dingbats?(?2700?-?27BF?)装饰标志 ?*?//Miscellaneous?Mathematical?Symbols-A?(?27C0?-?27EF?)杂项数学符号 ?*?//Supplemental?Arrows-A?(?27F0?-?27FF?)追加箭头 ?*?//Braille?Patterns?(?2800?-?28FF?)盲文点字模型 ?*?//Supplemental?Arrows-B?(?2900?-?297F?)追加箭头 ?*?//Miscellaneous?Mathematical?Symbols-B(?2980?-?29FF?)杂项数学符号 ?*?//Supplemental?Mathematical?Operators(?2A00?-?2AFF?)追加数学操作符 ?*?//Miscellaneous?Symbols?and?Arrows(?2B00?-?2BFF?)杂项符号和箭头 ?*? ?*?//CJK?Symbols?and?Punctuation(?3000?-?30FF?)CJK符号和标点 ?*? ?*?//Enclosed?CJK?Letters?and?Months(?3000?-?30FF?)CJK封闭式字符和月份 ?*? ?*?//?Mahjong?Tiles(?1F000?-?1F02F?)麻将牌 ?*?//?Domino?Tiles(?1F030?-?1F09F?)多米诺骨牌 ?*?//?Playing?Cards(?1F0A0?-?1F0FF?)扑克牌 ?*?//Enclosed?Alphanumeric?Supplement(?1F100?-?1F1FF?)封闭式字母数字补充 ?*?//Enclosed?Ideographic?Supplement?(?1F200?-?1F2FF?)封闭式表意文字补充 ?*?//Miscellaneous?Symbols?and?Pictographs?(?1F300?-?1F5FF?)其他符号和象形文字 ?*?//Emoticons?(?1F600?-?1F64F?) ?*?//Ornamental?Dingbats?(?1F650?-?1F67F?) ?*?//Transport?and?map?symbols?(?1F680?-?1F6FF?) ?*?//Alchemical?Symbols?(?1F700?-?1F77F?)炼金术的符号 ?*?//Geometric?Shapes?Extended?(?1F780?-?1F7FF?)几何图形扩展 ?*?//Supplemental?Arrows-C?(?1F800?-?1F8FF?)追加箭头-C ?*?//Supplemental?Symbols?and?Pictographs?(?1F900?-?1F9FF?)补充符号和象形文字 ?*?//Chess?Symbols?(?1FA00?-?1FA6F?)国际象棋的符号 ?*?https://en.wikibooks.org/wiki/Unicode/Character_reference ?* ?*?@param?codePoint ?*?@return ?*/ private?static?boolean?isEmojiCharacterByWiki(int?codePoint)?{ ????return?((codePoint?>=?0X2070)?&&?(codePoint?<=?0X2BFF))?|| ????????????((codePoint?>=?0X3000)?&&?(codePoint?<=?0X30FF))?|| ????????????((codePoint?>=?0X3200)?&&?(codePoint?<=?0X32FF))?|| ????????????((codePoint?>=?0x1F000)?&&?(codePoint?<=?0x1FA6F)); }
参考:
1.When the specification for the Java language was created, the Unicode standard was accepted and the char primitive was defined as a 16-bit data type, with characters in the hexadecimal range from 0x0000 to 0xFFFF.
Java语言标准创建的时候,就采纳了Unicode标准,char原始类型被定义为16-bit数据类型,能存储的字符范围用16进制表示是从0x0000到0xffff。
https://docs.oracle测试数据/javase/tutorial/i18n/text/unicode.html
2.The native character encoding of the Java programming language is UTF-16.
https://docs.oracle测试数据/javase/8/docs/api/java/nio/charset/Charset.html
3.维基百科对unicode编码的编排
https://zh.wikibooks.org/wiki/Unicode/%E5%AD%97%E7%AC%A6%E5%8F%82%E8%80%83/1F000-1FFFF
4.emoji编码分类
https://apps.timwhitlock.info/emoji/tables/unicode
查看更多关于unicode编码在Android中的应用的详细内容...