看Character和String的时候发现的小知识点,挺好玩的
不过这篇博客没提UTF-16,Java内部也是有做相应的处理的。UTF-16和UTF-8差别挺大的,感兴趣的话可以自己去看看:D
ASCII 码一共定义了 128 个字符,英语用 128 个字符来编码完全是足够的,但是用来表示其他语言,128 个字符是远远不够的。
Unicode是展示世界上所有语言中的所有字符的标准方案,他给所有的字符指定了一个数字用来表示该字符。但是Unicode并没有规定字符对应的二进制怎么存储。
因为字符很多嘛,所以就会有的字符需要两个字节,甚至三四个字节才能表示,如果直接全用四个字节表示那就太浪费空间。于是,为了较好的解决 Unicode 的编码问题, UTF-8 出现了。
UTF-8 是可变长编码。它可以使用 1 - 4 个字节表示一个字符,根据字符的不同变换长度。
编码规则如下:
对于单个字节的字符,第一位设为 0,后面的 7 位对应这个字符的 Unicode 码点。因此,对于英文中的 0 - 127 号字符,与 ASCII 码完全相同。
对于需要使用 N 个字节来表示的字符(N > 1),第一个字节的前 N 位都设为 1,第 N + 1 位设为0,剩余的 N - 1 个字节的前两位都设位 10,剩下的二进制位则使用这个字符的 Unicode 码点来填充。
Unicode 十六进制码点范围 | UTF-8 二进制 |
---|---|
0000 0000 - 0000 007F | 0xxxxxxx |
0000 0080 - 0000 07FF | 110xxxxx 10xxxxxx |
0000 0800 - 0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
0001 0000 - 0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
unicode的范围从000000 - 10FFFF,char的范围只能是在\u0000到\uffff。所以有的字符就需要两个char来表示,比如?? 对应的表示是 \uD83D\uDE03
,而如果只是截取一半,那这个字符是没有意义的。
在Java中,一个实际的完整的字符称作代码点(codePoint)
下面举个例子
String testCode = "ab\uD83D\uDE03";
int length = testCode.length();
int count = testCode.codePointCount(0, testCode.length()); //求出0到testCode.length()之间的代码点数目
System.out.println(testCode);
System.out.println("代码点数目:"+count);
//输出
ab??
代码点数目:3
所以如果要对字符串进行严格的过滤的话,应该按照代码点来进行访问,而不是逐位访问char
举个栗子:
String testCode = "ab\uD83D\uDE03汉字";
int cpCount = testCode.codePointCount(0, testCode.length());
System.out.println("cpcount:"+cpCount);
for (int index = 0; index < cpCount; ++index) {
//这里的i是字符的位置
int i = testCode.offsetByCodePoints(0, index);
//下个字符位置
int nexti = testCode.offsetByCodePoints(0,index+1);
int codepoint = testCode.codePointAt(i);
String cur = testCode.substring(i,nexti);
System.out.println("i:"+i+" index:"+index+ " cur:" + cur +"\tcodepoint:"+codepoint );
}
//输出
cpcount:5
i:0 index:0 cur:a codepoint:97
i:1 index:1 cur:b codepoint:98
i:2 index:2 cur:?? codepoint:128515
i:4 index:3 cur:汉 codepoint:27721
i:5 index:4 cur:字 codepoint:23383
关于Java的代码点(codePoint)、unicode编码、UTF-8
原文:https://www.cnblogs.com/sariseBlog/p/14946408.html