JAVA学习脚印10:解惑java 中UTF-16与char
JAVA学习脚印10:解惑java 中UTF-16与char
java中的char、utf-16编码、代码点、代码单元等概念,做一个了解还是有必要的。
1.基本概念
1) Java的字符类型和字符串类型
字符类型采用的是UTF-16编码方式对Unicode编码表进行表示。其中一个char类型固定2字节,为无符号数,表示范围为'\u0000'(0)~'\uffff'(65,535)。
java中的String定义如下:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
...
}
可见String内部使用char来存储字符的,且是不可变的,即java字符串是由char序列组成。
2) Unicode编码表的专业术语:
a. 代码点 (code point): 指在Unicode编码表中一个字符所对应的代码值。如汉字“一”的代码点是U+4E00,英文字母“A”的代码点是U+0041。
b. 代码单元( code unit): 规定16bits的存储容量就是一个代码单元。java中的一个字符char就对应一个代码单元,大多数uncode字符使用一个代码单元就够了,而辅助字符(见下文)需要一对代码单元。
可以这样构造字符数据:
如 char[] chs = {'\u2764','\u2602','\u2600','\u262F','\u262D','\u2622','\u260E'};
上面这几个字符比较流行,在GUI Jlabel中彩色打印出来如下图所示:
可以通过网站: http://unicode-table.com/en/#control-character
来获取你想要的unicode字符。
c. 代码级别 (code plane): Unicode编码表 ,分为17个代码级别 (code plane),其中代码点U+0000-U+FFFF为第一级别 ——基本多语言级别 (basic multiling l plane),可以用一个代码单元存储一个代码点。其余16个附加级别 从0x10000-0x10FFFF(需要两个代码单元)。
其中需要指出的是在多语言级别中,U+D800-U+DFFF这2048值没有表示任何字符,被称为Unicode的替代区域(surrogate area)。UTF-16正是的运用了这一区域,用2个代码单元(2*16bits)巧妙的表示出20bits代码点的Unicode附加级别。
3)UTF-16编码算法
假设U是一个代码点,也就是Unicode编码表中一个字符所对应的Unicode值。
1) 如果U<U+10000,也就是处于Unicode的基本多语言级别中。这样16bits(一个代码单元)就足够表示出字符的Unicode值。
2) 如果U+10FFFF>U>=U+10000,也就是处于附加级别中。UTF-16用2个16位来表示出了,并且正好将每个16位都控制在替代区域U+D800-U+DFFF 中了。
附加级别中的编码具体操作如下:
分别初始化2个16位无符号的整数 —— W1和W2。其中W1=110110yyyyyyyyyy(0xD800-0xDBFF),W2 = 110111xxxxxxxxxx(0xDC00-OxDFFF)。
U' = U - 0x10000(注意,网上很多博客中关于这个算法的存在错误,错误之处就是没有减去0x10000).
然后,将U'的高10位分配给W1的低10位,将U'的低10位分配给W2的低10位。这样就可以将20bits的代码点U拆成两个16bits的代码单元。
而且这两个代码点正好落在替代区域U+D800-U+DFFF中。而且w1和w2具有可区分性,0xD800-0xDBFF属于高代理项(high-surrogate),0xDC00-OxDFFF属于低代理项(high-surrogate)。
2.实例说明
这里举一个网上很多博客提到的比较经典的例子,U+1D56B:
该字符可以在 http://www.scarfboy.com/coding/unicode-tool?
网站上输入代码点后查看,看起来是这样的,
假设U = U+1D56B ,则U属于附加级别中的附加字符,那么可如下计算编码:
Step1:
U' = U- 0x10000 = 0x0D56B
= 0000 1101 0101 0110 1011
Step2 :
U'高十位: 0000 1101 01
U'低十位: 01 0110 1011
则w1 = 1101 1000 0011 0101 = 0xD835
w2 = 1101 1101 0110 1011 = 0xDD6B
至此将U+1D56B 编码为两个代码单元,第一个为0xD835,第二个为 0xDD6B 。
下面的代码可以加深对上述概念的理解:
package com.liucaijin.springboot2;public class UTF16Test {public static void main(String[] args) {String sample = null;if(args.length > 0) {sample = args[0];} else {// for the sake of not show the character of u+1D56BString special = new String(Character.toChars(0x1D56B));sample = special+" zZ" + special;}System.out.println("sample string is: "+sample);// String.length : Returns the length of this string.// The length is equal to the number of Unicode code units in the string.int len = sample.length();System.out.println("code units count: "+len);// traverse the string by code unitsSystem.out.print("code units are: ");UTF16Test.traverseByCodeUnits(sample);System.out.println();// get the number of Unicode code pointsint cpCount = sample.codePointCount(0, len);System.out.println("code points count: "+cpCount);// traverse the string by code point sSystem.out.print("code points are: ");UTF16Test.traverseByCodePoints(sample);System.out.println();}/*** traverse the string by code points* @param str the specified string to traverse*/public static void traverseByCodePoints(String str) {int cpCount = str.length();boolean flag = false;for(int ix = 0;ix < cpCount;ix++) {flag = printCodePoint(str.codePointAt(ix),flag);}}/*** traverse the string by code units* @param str the specified string to traverse*/public static void traverseByCodeUnits(String str) {int cuCount = str.length();for(int ix = 0;ix < cuCount;ix++) {String content = String.format("(%04x) ",(int)str.charAt(ix)).toUpperCase();System.out.print(content);//get code unit}}/*** print code point in hexadecimal form* @param cp the code point*/private static boolean printCodePoint(int cp,boolean flag) {//check if is the supplementary code pointif(Character.isSupplementaryCodePoint(cp)) {char[] chs = Character.toChars(cp);//stored the code point in UTF-16 representationString content = String.format("[U+%04x,U+%04x] ",(int)chs[0],(int)chs[1]).toUpperCase();System.out.print(content);return true;} else if(!flag) {String content = String.format("[U+%04x] ",cp).toUpperCase();System.out.print(content);return false;}return false;}}
不带参数时运行结果为 :
更多关于字符和字符串的操作可参考java官方API.
本文参考了博客:blog.csdn.net/fantasy0126/article/details/6050087
JAVA学习脚印10:解惑java 中UTF-16与char相关推荐
- JAVA学习脚印3: java语言控制流程
JAVA学习脚印3: java语言控制流程 本节首先介绍,java语言中的字符串处理以及输入输出控制,最后介绍控制流程. 在讲述控制流程之前,先介绍以下java中字符串和输入输出的内容,以便后续练习编 ...
- JAVA学习脚印2: 数据类型和运算符
JAVA学习脚印2: 数据类型和运算符 本节将记录java中的数据类型和运算符. 1. java中的数据类型 java中变量的数据类型有两种:基本类型(primitive)和引用(reference) ...
- JAVA java学习(9)——————java常用开发工具介绍
下面这些工具或许功能和作用不同,但是有着一个共同的主旨,那就是--它们都是为了给 Java 编码和开发提供卓越的支持. 常用源码编辑工具介绍 ava 源代码本质上其实就是普通的文本文件,所以理论上来说 ...
- [Java学习探讨]为什么学Java虚拟机的Java程序员更有价值?
个人博客导航页(点击右侧链接即可打开个人博客):大牛带你入门技术栈 [Java学习探讨]为什么学Java虚拟机的Java程序员更值钱? 曾经的我经常害怕处理与JVM相关的异常,对JVM的配置参数也一无 ...
- springboot毕设项目java学习平台m55rv(java+VUE+Mybatis+Maven+Mysql)
springboot毕设项目java学习平台m55rv(java+VUE+Mybatis+Maven+Mysql) 项目运行 环境配置: Jdk1.8 + Tomcat8.5 + Mysql + HB ...
- Java学习系列(十八)Java面向对象之基于UDP协议的网络通信
UDP协议:无需建立虚拟链路,协议是不可靠的. A节点以DatagramSocket发送数据包,数据报携带数据,数据报上还有目的目地地址,大部分情况下,数据报可以抵达:但有些情况下,数据报可能会丢失 ...
- Java学习系列(十六)Java面向对象之基于TCP协议的网络通信
TCP/IP的网络分层模型:应用层(HTTP/FTP/SMTP/POPS...),传输层(TCP协议),网络层(IP协议,负责为网络上节点分配唯一标识),物理层+数据链路层). IP地址用于标识网络中 ...
- Java学习练习题08:Java习题及代码08
Java学习练习题08: Java习题及代码08: 链接:https://pan.baidu.com/s/1_PCPo7SI2fRFph02l2UCpQ 提取码:zapx
- JAVA学习 11.10
Java第一天 1.1 Java发展史 1995年,SUN虽然推出了Java . 詹姆斯 高瑟林[java之父]带领自己的团队研发了java编程语言. 后来有一个公司就整了一个开发软件 Eclipse ...
最新文章
- 数据缺失、混乱、重复怎么办?最全数据清洗指南
- 脚本修改linux网络配置,用脚本实现Linux的网络配置
- 实例详细讲解ASP生成静态页面方法
- 香港大学顾佳涛:非自回归神经机器翻译 | 直播预告
- .NET程序员应该理解的几种软件保护方法 辛苦开发的程序需要建立有效的保护机制...
- python34.dll_python34.dll下载
- python实例 85,86
- java 十进制 左移,java移位运算符之十进制转二进制
- 易语言注入 c dll,易语言DLL注入模块简单型
- 关于升级Vmware ESXI6.7 主机挂在ISCSI共享存储的方法
- java加载阶段内存分配_Java核心:类加载和JVM内存的分配
- C++ 对Ctrl+Z的解释
- GOM引擎ItemShow代码在NPC对话框中显示装备图片及属性
- 百度C语言面试题2017,百度C语言面试题
- 【位操作笔记】计算以10为底整数N的对数 普通方法
- 内网穿透到cs上线--部署到公网上!!
- 基于HTML贪吃蛇游戏摘要,基于JavaScript实现贪吃蛇游戏
- 介绍一种冷门但简单的双拼方案——紫光双拼
- between oracle的用法,关于 oracle between and的用法! | 学步园
- 苹果M1 Mac 如何卸载 iPhone 和 iPad 应用程序?