本以为汉字编码是一个比较无聊的问题,但是经过昨天一天的探索和学习,发现其实这是一个蛮有意思的问题,在这个过程中我也学到了不少新的姿势,拿出来和大家分享一下。
首先必须是Unicode和UTF-8相互转来转去的问题,其实这个是有规律的,比如说汉字”吴“的Unicode编码为5434(16进制),那么它对于的二进制应该就是
0101 0100 0011 0100,接下来从后往前取6位,把它分成0101 0100 00和11 0100,在截下来的前面补上10,就变成了1011 0100,继续这个步骤,把
0101 0100 00分为0101和0100 00,还是补上10,变成1001 0000,最后一段没到6位(0101),则说明该汉字用UTF-8存储需要3字节,故第一字节前四位为1110(三个字节所以三个1110,两个字节为两个110,一个字节只有0,UTF-8最多6个字节),所以第一个字节为1110 0101,把得到的三个字节,即111001011001 00001011 0100,转换成16进制,就是对应的UTF-8编码——E590B4。
从UTF-8换算成Unicode方法一样,只不过是倒推而已。比如”屋“的UTF-8编码为E5 B1 8B,先转成111001011011 00011000 1011,即其Unicode的二进制为
0101 1100 0100 1011,转成16进制,即5C4B。
前面将了一大堆,其实无非就是想说明,有目前计算机有多种编码方式,其中大家用的中文系统一般都是GBK编码的(GBK包括GB2312,来源请看昨天转载的文章),而目前主流最通用的编码方式为UTF-8,而UTF-8又是Unicode的一种实现。
接下来是我今天发现的一个小问题,我发现Java在存储char的时候,不管你项目怎么设置,就算编译指定为UTF-8,也不能改变其对char的编码方式——Unicode,这也就是为什么我可以通过一下这段断码来判断该字符是否为汉字!
char word = '你';
String regEx = "[//u4e00-//u9fa5]";
assert Pattern.matches(regEx, String.valueOf(word));
由于时间关系,今天先接到这里,明天继续编辑,下面的代码是在写随机生成汉字时用到的,也是一个学习的过程,让我对Java IO有了更深刻的认识。
package nero.test;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
public class AlwaysTest {
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
String filePath = ".\\surname1.txt";
File file = new File(filePath);
FileInputStream fin = new FileInputStream(file);
BufferedInputStream bin = new BufferedInputStream(fin);
//读取文本文件头信息,判断文本文件为哪种类型的编码方式
int code = (bin.read() << 8) + bin.read();
String codeType = null;
switch (code) {
case 0xefbb:
codeType = "UTF-8";
break;
case 0xfffe:
codeType = "Unicode";
break;
case 0xfeff:
codeType = "UTF-16BE";
default:
codeType = "GBK";
}
bin.close();
fin.close();
fin = new FileInputStream(file);
InputStreamReader reader = new InputStreamReader(fin, codeType);
BufferedReader bufferedReader = new BufferedReader(reader);
String regEx = "[\\u4e00-\\u9fa5]"; // 汉字Unicode范围
List<String> subname = new ArrayList<String>();
int temp;
/*
* 这一个循环其实非常有意思
* 开始文件是以UTF-8读入的
* 但是这里转成char后,得到的却是Unicode的编码
* 我的项目编码方式也是UTF-8,这就说明数据在被读入的时候进行了转码运算
* 怀疑是InputStreamReader做的,因为它是按照字符来读入的(注意是字符,不是字节)
* 为了证明这一结论,输出了temp的值,其中汉字“李”的输出值为26446,上网查其Unicode为674E
* 两值正好相等,证明了结论,同时也印证了Java中char都是按照Unicode编码存储的!
*/
while ((temp = bufferedReader.read()) != -1) {
System.out.println(temp);
char word = (char) temp;
if (Pattern.matches(regEx, String.valueOf(word))) subname.add(String.valueOf(word));
}
bufferedReader.close();
reader.close();
fin.close();
for (int i = 0; i < subname.size(); i++) {
System.out.println("surname[" + i + "] = \"" + subname.get(i) + "\";");
}
System.out.println(subname.size());
}
}