`
weiyinchao88
  • 浏览: 1185202 次
文章分类
社区版块
存档分类
最新评论

正确理解各种编码问题

 
阅读更多
如果你开发过的软件项目中涉及到多语言支持的问题,那么相信你没少碰到过乱码问题,然后在寻求解决问题的途径过程中被一些概念如ASCII, ISO-8859-1, Unicode,UTF-8,GBK,GB2312等等所困扰。本文有助于你正确的理解这些概念。
1. ASCII
用7位编码将英文字符和一些常用的符号存诸为从0到127的数值。
2. ISO-8859-1
法语、西班牙语和德语之类的西欧语言都使用叫做ISO-8859-1的编码系统(也叫做“latin-1”)。它使用7位ASCII字符表示从0到127的字符,但接着扩展到了128-255的范围来表示如n上带有一个波浪线(241),和u上带有两个点(252)的字符等等。可以说ASCII是ISO-8859-1的子集。
3. Unicode
Unicode用一个2字节数字表示每个字符,从0到65535。每个 2 字节数字表示至少在一种世界语言中使用的一个唯一字符。(在多种语言中都使用的字符具有相同的数字码。)这样就确保每个字符一个数字,并且每个数字一个字符。Unicode数据永远不会模棱两可。Unicode使用相同的数字表示ASCII和ISO-8859-1中的字符。只是这两种编码用一个字节表示,而Unicode用两个字节表示。所以Unicode表示这两种编码的字符时只要用低字节就可以了,高字节为0。
4. UTF-8
UTF-8是一种变长的编码方式,每个UTF-8的编码可以是1至6个字节长。它将Unicode编码的字符采用变长的方式进行编码。对Unicode中属于ISO-8859-1的编码采用和ISO-8859-1相同的单字节编码。其他字符采用两字节以上的编码。实际上对于两个字节的Unicode编码,UTF-8只要三个字节即可表示。第一个字节由n个1(1< n <= 6)开始, n表示编码的字节数,后面每个字节都以10开始,后面6位为有效位。将第一位的剩余位和后面的所有字节的后六位连接起来就是对应的Unicode编码的数值。例如汉字“中”的编码:
Unicode: 4E 2D
01001110 00101101
UTF-8: E4 B8 AD
11100100 10111000 10101101
可以通过以下方式进行证实:
用记事本创建一个文本文件,输入汉字“中”分别保存为Unicode格式和UTF-8格式。 将UltraEdit的自动识别UTF-8文件格式选项禁止,然后用其打开这两个文件,选用二进制查看方式,可以看到:
UTF-8格式文件编码为“EF BB BF E4 B8 AD”。其中有个三字节的前缀“EF BB BF”,这是UTF-8格式文本文件的标识。不过这个前缀不要,某些文本查看软件也可以通过编码判断出UTF-8格式。“E4 B8 AD”就是“中”的UTF-8编码。
Unicode格式的文件的完整编码是“FF FE 2D 4E”。前面有个双字节前缀“FF FE”,这是Unicode格式文本文档的编码标识。而我们看到的编码是“2D 4E”,而不是如我前面所说的“4E 2D”,为什么呢?因为数字是按照低字节在先高字节在后的顺序存储的,所以实际的Unicode编码恰恰是“4E2D”。
5. GB2312和GBK
这两种编码都是汉字的编码标准,其中前者是后者的子集。GBK编码的文本文档中对于ASCII中的字符用相同的单字节表示;对于汉字和汉语中的标点符号等采用双字节编码,其中高字节大于0x80,而ASCII的所有字符的编码均小于0x80, 所以ASCII和GBK的字符是可以混和起来的。GBK的字符集和Unicode进行转换是无规则的,需要转换表才能进行转换。
6.下面给出我用Java语言写的Unicode和UTF-8转换的程序片段,供大家参考。
因为Java语言的字符使用Unicode编码的,所以程序中是对UTF-8编码的字符串的字节数组和Java的String类型进行转换。String对象中的每一个Character就是一个Unicode编码的字符。
public String utf8Bytes2String(byte[] buff){
if(buff == null)
return null;
StringBuffer sb = new StringBuffer();
int idx = 0;
if(buff[0] == (byte)0xEF &&
buff[1] == (byte)0xBB &&
buff[2] == (byte)0xBF)
idx = 3;//Skip UTF8 header
while(idx < buff.length){
int hB = buff[idx] & 0xFF;
int bCnt = 0;
int check = 0x80;
for(int i=0; i<8; i++){
if((hB & check) != 0){
bCnt ++;
check >>= 1;
}else
break;
}
if(bCnt <= 1){
char c = 0;
c |= buff[idx] & 0xFF;
sb.append(c);
idx++;
}else if(bCnt == 2){
char c = 0;
c |= buff[idx] & 0x03;
c <<= 6;
if((buff[idx+1] & 0xC0) != 0x80)
return null;
c |= buff[idx+1] & 0x3F;
idx += 2;
sb.append(c);
}else if(bCnt == 3){
char c = 0;
c |= buff[idx] & 0x0F;
c <<= 6;
if((buff[idx+1] & 0xC0) != 0x80)
return null;
c |= buff[idx+1] & 0x3F;
c <<= 6;
if((buff[idx+2] & 0xC0) != 0x80)
return null;
c |= buff[idx+2] & 0x3F;
idx += 3;
sb.append(c);
}else
return null;
}
return sb.toString();
}
public byte[] string2Utf8Bytes(String str){
if(str == null)
return null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
string2Utf8Stream(str, bos);
} catch (IOException e) {
e.printStackTrace();
}
return bos.toByteArray();
}
public void string2Utf8Stream(String str, OutputStream os) throws IOException {
if(str == null || os == null)
return;
for(int i=0; i<str.length(); i++){
char c = str.charAt(i);
if(c < 0x80){
os.write((byte)c);
}else if(c >=0x80 && c < 0x100){
int hi = c >> 6;
hi |= 0xC0;
int lo = c & 0x3F;
lo |= 0x80;
os.write(hi);
os.write(lo);
}else{
int first = c >> 12;
first |= 0xE0;
int second = c >> 6;
second &= 0x3F;
second |= 0x80;
int third = c & 0x3F;
third |= 0x80;
os.write(first);
os.write(second);
os.write(third);
}
}
}
参考:由一节废电池引起
分享到:
评论

相关推荐

    字符,字节和编码.中文问题”,“乱码问题”。

    本文介绍了字符与编码的发展过程,相关概念的正确理解。举例说明了一些实际应用中,编码的实现方法。然后,本文讲述了通常对字符与编码的几种误解,由于这些误解而导致乱码产生的原因,以及消除乱码的办法。本文的...

    C Primer Plus第6版中文版编程练习答案 练习题帮助初学者巩固和深化对C语言的理解,提升他们的编程技能和解决问题的能力

    提升问题解决能力: 练习题涉及各种问题,从简单的计算到复杂的逻辑判断。通过解决这些问题,学习者能够培养解决实际问题的思维能力。 巩固算法思维: 练习题中的一些问题需要学习者设计算法来解决,这有助于培养...

    java字符编码

    本文介绍了字符与编码的发展过程,相关概念的正确理解。举例说明了一些实际应用中,编码的实现方法。然后,本文讲述了通常对字符与编码的几种误解,由于这些误解而导致乱码产生的原因,以及消除乱码的办法。本文的...

    eclipse文件编码设置、转换原理与实用工具

    3.文件编码的自动设别方法与测试示例(自动列出编码、最可能的编码、有多种编码可能的情况下打印用各种编码解码出来的内容以便核对,下载文件中附带乱码的文件例子和正确的读取方法)。 声明: 除了“文件编码的...

    字符,字节和编码基础知识

    本文介绍了字符与编码的发展过程,相关概念的正确理解。举例说明了一些实际应用中,编码的实现方法。然后,本文讲述了通常对字符与编码的几种误解,由于这些误解而导致乱码产生的原因,以及消除乱码的办法。本文的...

    信息论之信源哈夫曼(Huffman)编码

    此为帮别人做的一个信息论哈夫曼程序,通过信源个数,信源权重进行编码,可得到平均码长和编码效率,代码有注释,方便理解。

    PCM编码器与PCM解码器的MATLAB实现及性能分析

    通过本课程的学习我们不仅能加深理解和巩固理论课上所学的有关 PCM编码和解码的基本概念、基本理论和基本方法,而且能锻炼我们分析问题和解决问题的能力;同时对我们进行良好的独立工作习惯和科学素质的培养,为今后...

    操作系统入门与实践-参透技术本质完结9章

    理解操作系统有助于问题排查以及bug调试,比如利用多线程来优化程序性能、利用系统调用跟踪工具排查各种系统层面的疑难杂症、利用内存管理知识深刻理解程序与内存是怎样交互的等等,从此你不必再去求别人帮你排查...

    gbk utf8如何选择 正确理解和使用GBK及UTF-8网页编码

    网页编码英文译为web page encoding,是在网页中指定其特定的字符编码格式的库。 GBK是国家标准GB2312基础上扩容后兼容GB2312的标准。GBK的文字编码是用双字节来表示的,即不论中、英文字符均使用双字节来表示,为了...

    关于软件工程的编码与测试

    个人使用 做为软件工程过程的一个阶段,程序编码是设计的继续。...为了保证程序编码的质量,程序员必须深刻理解、熟练掌握并正确地运用程序设计语言的特性。此外,还要求源程序具有良好的结构性和良好的程序设计风格。

    论文研究 - 耳蜗外脉冲电刺激系统的语音编码方案

    已经研究了一种耳蜗外刺激系统,... 结果表明,正确识别的元音和辅音的比​​率显着高于对照刺激,表明CMS可以产生至少部分可理解的元音和辅音感知。 总之,可以将语音编码方案应用于耳蜗外刺激系统以恢复语音感知。

    字符,字节和编码

    Java处理中文时经常给大家带来方框或者乱码。只有理解了字符,字节和编码的关系,才能正确处理Java中的中文(当然也包括其它文字)

    Java编码规范V1.0.pdf

    编码规则是程序编码所要遵循的规则,要注意代码的正确性、稳定性、可读性。要避免使用不易理解的数字,用有意义的标识来替代,不要使用难懂的技巧性很高的语句。源程序中关系较为紧密的代码应尽可能相邻。

    Google的C++编码规范 中文.PDF

    为什么pdf内正确的字复制...限制甚至禁止使用某些特性使代码简化,避免可能导致的各种问题,挃南中列丼了返类特性,幵解释说为 什么返些特性是被限制使用的。 注意:本挃南幵非 C++教程,我们假定诺者巫经对 C++非常熟恲。

    关于dom和jquery对象理解

    关于dom和jquery对象理解

    .net官方编码方法和命名规则

    对于理解应用程序的逻辑流,命名方案是最有影响力的一种帮助。命名原则是:选择正确名称时的困难可能表明需要进一步分析或定义项的目的。使名称足够长以便有一定的意义,并且足够短以避免冗长。唯一名称在编程上仅...

    C++编码规范

    • 方便代码的交流和维护...• 不影响编码的效率,不与大众习惯冲突。 • 使代码更加美观、阅读更为方便。 • 正确、简单和清晰第一,坚持KISS(Keep It Simple Software)原则。 • 使代码的逻辑更清晰、更易于理解。

    计算机网络常见问题解答

    问题4-14:IP地址中的各种类别的地址所拥有的地址数目的比例是怎样的? 问题4-15:在IP地址中,为什么使用最前面的一个或几个比特来表示地址的类别? 问题4-16:全1的IP地址是否是向整个因特网进行广播的一种地址? ...

    Python机器学习项目开发实战_可视化数据_编程案例解析实例详解课程教程.pdf

    在现实世界中总会存在各种数值数据,我们想将这些数值数据编码成图、线、点、条等,以便直观地显示这些数值中包含的信息,同时可以使复杂分布的数据更容易被理解和应用。这一过程被广泛应用于各种场合之中,包括对比...

Global site tag (gtag.js) - Google Analytics