本以为汉字编码是一个比较无聊的问题,但是经过昨天一天的探索和学习,发现其实这是一个蛮有意思的问题,在这个过程中我也学到了不少新的姿势,拿出来和大家分享一下。
首先必须是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()); } }