字符编码简介

ASCII(American Standard Code for Information Interchange,美国信息互换标准代码)html

它使用0-127 之间的数字来表示数字、字母、符号等可见字符和一些控制字符,这个字符集的编码就肯定了ASCII字符集。而这个字符集要想要在计算机的二进制方式下使用就必须用计算机可以理解的方式来处理,ASCII使用了一个计算机字节来表示这种编码方式java

GBKlinux

GBK,你们都知道,汉字内码扩展规范GBK是怎么来的呢?GBKGB2312扩展来的,GB2312是最先的中文编码方式。GB2312又是怎么来的呢?chrome

计算机发展到80年代在中国开始慢慢的兴起。为了可以让中国人可以更好的使用计算机天然要引入中文编码到计算机中。可是引入中文编码遇到了一个问题,就是ASCII使用一个字节来编码字符,可是中国的汉字是确定不可以在一个字节中表示彻底,怎么办?聪明的中国人发现一个字节可表示的最大区间是0-255,而ASCII只使用了0-127,128-255并无使用,那么咱们就能够用多个字节来表示中文编码好比:一个字节(char)的值是在0-127之间,咱们就仍是用这个字节来表示ASCII里面的字符,也就是说兼容ASCIIwindows

一个字节(char)的值是在128-255之间(此处假设是130),则说明它不是在ASCII字符集里面的,那它表示什么字符呢?此种状况下,则要在读取下一个字节的值(此处假设是10),那么就将两个字节的值:13010按照某种计算规则来计算等到一个值,此处计算获得3290,那么这个值能够在一个字符编码表中去查,它可能获得某个汉字,此处假设为‘字’字而后就能够在屏幕上显示出来了。(此处的计算都是假设,我没有详细查,之后有时间再更正,理解原理便可。也能够查看维基百科了解详细。浏览器

GBK中有哪些字符?app

GBK是微软利用GB2312未使用的编码空间,收入GB13000.1的所有字符制定而来。GBK是用来编码中文汉字的,而且兼容ASCII字符集。GBK中是否是只有简体中文呢?由于简体汉字和繁体汉字有很大一部分是相同,把常见的几千个繁体中文里面的汉字编码进来也不会多多少,所以,GBK里面也是有繁体中文汉字的。除此以外还有什么,由于如今简体和繁体的常见字都编码了,那日文里面的大多数文字也都在其中,只须要将日文的平假名和片假名(也就几十个字符)编码进来。所以,GBK里面是有常见的简体中文、繁体中文、日文等字符在一块儿的字符集。编辑器

Big5等编码ide

中国人发明了多字节编码的方式,可是只能编码中国汉字(包括简繁和日文)。其余国家和中国台湾想要编码文字天然就会采用类似的方式来编码,Big5等编码方式就产生了,它们一样按照某种计算方式计算出值,此处假设仍是3290,可是他们的编码表和GBK不同,因此他们表明的文字就不在是‘字’了。测试

Windows ANSI编码

GBK、Big5等编码就是ANSI编码,也叫本地码。ANSI编码就是本地码的统称,就是在什么国家或地区就是什么编码好比在中国的大陆地区就是GBK,在中国台湾就是Big5

乱码

乱码,很常见也很烦的一个Bug,编码Bug

假设咱们在简体中文的机器上,那么本地码是GBK,咱们用它编码了一文字保存在txt文件里面,而后把它拷贝到繁体中文的机器上,此处的本地码是Big5,而后打开这个文件,假设咱们使用记事本打开,它打开文件使用的默认编码就是本地码,即Big5,按照Big5的方式计算值,并依次查字符编码表,而后显示出来。乱码来了,原本在GBK中编码的有意义的字句,在Big5下计算查表出来获得的是一文字字符,而这文字字符链接在一块儿没有任何意思,所以乱码。

乱码和字体

乱码是编码引发的,而在文字显示时是要去字体中查询到某个字符的形状,而后显示,有可能出现字体里面没有这个文字,那么就会用一个默认的字符显示,此时给人的感受也像乱码,一般表现出不少个字符都是一个样子(好比一个白框),可是它不是乱码,只是字体中没有文字的信息,换个字体就能显示。

UNICODE

随着互联网的发展,各个国家基本上都有本身的本地编码ANSI编码。为此,系统要支持多过的本地编码,怎么办?引入代码页code page,根据代码页号去查相应的字符集,GBK的代码页就是CP936(有细微差异,详细能够查看维基百科)

可是代码页仍是不能将不一样字符集中的字符在同一系统中显示,好比:汉字和阿拉伯文不能同时显示。UNICODE诞生了。

UNICODE就是要将全部的字符所有编码在一个字符集里面,好比1-10000编码简体中文,10001-20000编码繁体中文,依次类推,这样就构成了UNICODE字符集。可是UNICODE字符集并没说要怎么编码,只是说某个数字表明某个字符,即之规定了数字到字符的的字典,可是没有规定在计算机中怎么编码。

UCS(Universal Character Set)/UTF(Unicode transformation format)

为了在计算机中编码字符,就出现了UCS/UTF编码,常见的有UTF-8UTF-16UCS-2),UTF-32UCS-4)编码。

UTF-8是相似GBK编码的一种编码,就是用多个字节编码计算出值而后查表,它能够是一个字节(也就是兼容ASCII)表示一个字符,能够是两个、三个、四个或者更多个字节根据计算获得某个值,而后去查UNICODE表获得某个字符,这样就将全部字符进行了编码。

UTF-16则至少是须要两个字节来表示,也就是说,能够由两个字节计算获得某个值,也能够是四个字节、六个字节、八个字节计算出值而后查表获得字符。

UTF-32则至少是须要四个字节表示,以此类推

C/C++中的编码

char在C/C++中表示一个字节,一般也用它来表示编码字符,若是它编码的字符是ASCII编码,则是每一个字节都表示一个字符,也就是说每一个char表示一个字符。若是编码是ANSI,此处假设是GBK编码,那么能够是一个char表示的字符,也能够是两个char表示一个字符。若是是UTF-8编码,那么能够是一个char、两个char、三个char或者更多来表示一个字符。

wchar_t是C/C++中的宽字符,标准没有规定它占几个字节,只是规定用来编码unicode字符集,一个wchar_twindowswchar_tUTF-16编码)下面占2个字节,在linuxwchar_tUTF-32编码)下面占4个字节,用wchar_t来编码unicode的话,常见字符均可以用一个wchar_t来表示。可是unicode字符集一直在扩充引入更多的字符,因此颇有可能一个wchar_twindows)不能表示出80001号字符,那么也就出现两个wchar_t表示一个字符,这也就正好符合UTF-16编码的规则。

C/C++中的乱码解决方法

乱码实际上是无解的。大多数软件的软件的处理方式就是只处理UNICODEUTF-8ANSI编码,所以一段文字的ANSI编码和打开机器的本地码不同那么就必然出现乱码,固然若人为的告诉软件说这段文字是某个code page编码的,那么仍是能够正确显示,可是这是依靠人为操做了。

软件里面处理这个问题处理的最好的有一类软件,就是浏览器。浏览器检测文本编码的方式一般就是猜,猜它是哪一种编码,猜完是哪一种编码以后就用相应的code page去查字符,而后显示。那么这个猜是否是乱猜呢?不是,是经过逐个字节扫描进行统计,看看这段文本最多是哪一种编码。固然这样作也会有错误,那么也同样会出现乱码,可是出现乱码的概率已经很低了。(想详细了解能够查看firefoxchrome的源码)

看不懂比乱码好

假设一个程序是用的是GBK编码的字符串,那么在一个日文操做系统(Windows)上,软件的字符那将是乱码,这给人一个很很差的感觉。即便此软件没有日文版,可是若是可以将简体中文正确的显示出来那仍是要好上许多的,说不定使用软件的人仍是个懂中文的人。

C++里怎么作?Windows从NT开始就支持宽字符版本的API,对于全部使用API的地方都是用宽字符版本就可以正常的显示出文字了,在C++中就是使用wchar_t。好比:

wchar_t *wstr = L"中文";

而后用对应的宽字符版本的API来显示出来就能够了。那是否是程序内部所有都应该使用wchar_t来表示字符?我我的推荐只在Windows下运行的程序这么作,也就是跟字符显示不相关的东西也使用wchar_t来表示。固然,也能够根据状况在只在显示字符的时候经过调用 MultiByteToWideChar将其它编码的字符转换成宽字符来显示,这样显示不相关的字符就可使用多字节字符集(ANSI、UTF-8)了。

对于跨平台的软件(Windows、Linux),我我的推荐使用UTF-8编码的字符来做为内部处理的字符,这样在只须要在字符显示的地方转换成相应的编码就能够了。固然主要仍是在Windows上面作处理,调用MultiByteToWideChar将UTF-8转换成宽字符而后显示。

UTF-8在C++ 98中的表示

在目前的C++标准中,咱们一般不能直接在代码里面写出UTF-8编码的字符串常量。

char *str = "中文"; // 对于VS,只有源文件是不带BOM的UTF-8编码时才是UTF-8字符串,对于带BOM的UTF-8编码或者GBK编码的文件都是GBK的字符串;
                    // 对于GCC,源文件编码是什么那么这个字符串的编码就是什么。

wchar_t *wstr = L"中文"; // 这里使用的是unicode编码

可是,由于ANSI编码和UTF-8编码都是兼容ASCII编码的,因此咱们能够在代码里面这样写:

char *str = "abc";  // 此处的编码是ASCII、ANSI、UTF-8

也就是上面这段字符是能够当成ANSI编码也能够当成是UTF-8编码的,那么咱们就能够将它当成UTF-8编码来使用。因此在代码里面最好不要出现字母之外的字符。(固然,不考虑多语言版的话除外

那咱们要与用户交互的时候不能是英文字母啊咱们能够从资源文件中读取,即咱们能够将要显示的字符放置到ini、XML以及其它文本文件中,这些文件以UTF-8编码。这样咱们程序就从资源文件中读取这些UTF-8编码的字符就能够了。这也就能够很好的作多语言版本了,只要将资源文件中的字符改为其它语言的字符就能够了,固然编码仍是UTF-8。(Windows下窗口相关的资源.rc也使用UNICODE编码就行)

这样作值得么?值得不值得就看咱们的程序是否是须要作多语言版,或者未来要不要作多语言版,若是要,这就是值得的,不要固然就无所谓了。

UTF-8在C++ 11中的表示

C++ 98中不能写出UTF-八、UTF-1六、UTF-32的字符串常量,C++ 11加入了新字符类型char16_t和char32_t,其相应的常量表示以下:

u8"中文"; // 表示用UTF-8编码的字符串常量

u"中文";  // 表示用UTF-16编码的字符串常量

U"中文";  // 表示用UTF-32编码的字符串常量

Java中的编码

源代码文件采用的编码方式取决于你所采用的编辑器设定,GBK、GB23十二、GB18030、UTF-8等等。Java编译器会根据源码产生class文件,这里的class文件编码是UTF-8编码。可是当JVM执行class文件时,采用的确实UTF-16编码。

测试代码(JDK6):

import java.io.UnsupportedEncodingException;

public class Test {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		System.out.println("gbk : \t\t" + getCode("雷", "gbk"));
		System.out.println("gb2312 : \t" + getCode("雷", "gb2312"));
		System.out.println("gb18030 : \t" + getCode("雷", "gb18030"));
		System.out.println("iso-8859-1 : \t" + getCode("雷", "iso-8859-1"));
		System.out.println("unicode : \t" + getCode("雷", "unicode"));
		System.out.println("utf-16 : \t" + getCode("雷", "utf-16"));
		System.out.println("utf-8 : \t" + getCode("雷", "utf-8"));

		System.out.println(Integer.toHexString("雷".codePointAt(0)).toUpperCase());
	}

	public static String getCode(String content, String format) {
		byte[] bytes = null;
		try {
			bytes = content.getBytes(format);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < bytes.length; i++) {
			sb.append(Integer.toHexString(bytes[i] & 0xff).toUpperCase() + " ");
		}

		return sb.toString();
	}
}

结果输出:

编译后的class文件二进制:

参考资料:

http://www.cnblogs.com/lidabo/p/3317770.html

http://www.cnblogs.com/leesf456/p/5313408.html

相关文章
相关标签/搜索