本文主要介绍java字符的编码方式,包括unicode编码、码点、char类型、string类型等
1、char与unicode的关系与区别
unicode编码方式的出现原因正如其名,是为了统一各种字符编码的标准。在设计之初由于未能考虑到中文、日文等表意文字,所以仅仅才用了2个字节,也就是16位的编码方式,最多能容纳65536个字符,这种2字节标准的unicode编码称作UCS-2。与此同时java中char类型也采用了2个字节数的设计方法。因为char可以刚好表示UCS-2的所有字符。但是很快UCS-2就不够用了,之后又出现了UCS-4,即采用4个字节的的编码方式,此时char就不够用了。
2、char类型在java中表示
在讨论java如何解决USC-4所带来的char长度不够用带来的问题之前,我们先讨论java中char类型的表示方式。
//1. 符号表示
char a = 'A';
//2. 十六进制表示,\u转义序列表示转为字符
char b = '\u2122';
//或
String c = "\u2122";
16进制的表示方式刚好表示:\u0000-\uffff(从0000到ffff个字符),USC-2中所有字符。
3、char类型如何表示UCS-4
首先说明两个概念:
码点:一个编码表中的某个字符对应的代码值。例如:\u2122就是一个码点
代码单元:一个char类型表示的编码范围。
例如:"\uD835\uDD46"是一个又两个代码单元构成的码点。
为了表示USC-4表示的字符,java采取的方式很简单,采用两个代码单元表示一个USC-4字符
对于UCS-2中的字符,使用一个代码单元就够了。
String b = "\uD835\uDD46";
System.out.println(b);
上述输出为:
4、java代码中如何操作码点
参考下述代码,输出正确吗?
String b = "\uD835\uDD46\u0001";
for (int j = 0; j < b.length(); j++) {
System.out.println(b.charAt(j));
}
输出:
这个输出明显是不正确的,因为String b = "\uD835\uDD46\u0001";
是由两个字符组成的,第一个字符是一个UCS-4的字符,由两个代码单元构成。
因此可以看到,string.length()
获取的是代码单元的数量,是按代码单元遍历的,一旦出现双代码单元的字符就会出问题。
那么如何按码点遍历呢?
1.码点的基本操作
//1.获取码点的数量
String str = "test\uD835\uDD46";//5个码点
int cpCount = str.codePointCount(0, str.length());
System.out.println(cpCount);//输出5
//2.获取第i(i=5)个码点,打印码点和字符
int cp5 = str.offsetByCodePoints(0, 4);
int cpi = str.codePointAt(cp5);
System.out.println(cpi+"-->"+(char) cpi);
System.out.println();
//3.获取字符串的码点数组
int[] cpArray = str.codePoints().toArray();
//4.将码点数组转换成字符串
String s = new String(cpArray, 0, cpArray.length);
System.out.println(s);
//5.判断是否时由双代码单元构成的字符,是返回true,否则返回false
Character.isSupplementaryCodePoint(int cp)
2.遍历字符串
//获取字符串的码点数组,并根据码点遍历数组
String str = "test\uD835\uDD46";//5个码点的字符串
int[] cpArray = str.codePoints().toArray();
for (int cpA : cpArray) {
System.out.print(cpA+"-->"+(char)cpA+"\t");
}
System.out.println();
//根据字符单元遍历字符串
for (int j = 0; j < str.length();) {
//获取第j个码点
int iCP = str.codePointAt(j);
if(Character.isSupplementaryCodePoint(cpArray[j])){
j+=2;
}else {
++j;
}
System.out.println((char)iCP+"\t");
}