字符集与字符编码

上传人:ldj****22 文档编号:41124601 上传时间:2018-05-28 格式:DOC 页数:29 大小:141.50KB
返回 下载 相关 举报
字符集与字符编码_第1页
第1页 / 共29页
字符集与字符编码_第2页
第2页 / 共29页
字符集与字符编码_第3页
第3页 / 共29页
字符集与字符编码_第4页
第4页 / 共29页
字符集与字符编码_第5页
第5页 / 共29页
点击查看更多>>
资源描述

《字符集与字符编码》由会员分享,可在线阅读,更多相关《字符集与字符编码(29页珍藏版)》请在金锄头文库上搜索。

1、字符集则在内存的相应区域,这个字符就表示为 0x6C49。可以用下面的代码证明一下:char han = 汉;System.out.format(“%x“,(short)han);输出是:6c49反过来用 UTF-16 编码来指定一个字符也可以,像这样:char han=0x6c49;System.out.println(han);输出是:汉这其实也是说,只要你正确的读入了“汉”这个字,那么它在内存中的表示形式一定是 0x6C49,没有任何其他的值能代表这个字。JVM 的这种约定使得一个字符存在的世界分为了两部分:JVM 内部和 OS的文件系统。在 JVM 内部,统一使用 UTF-16 表示,

2、当这个字符被从 JVM 内部移到外部(即保存为文件系统中的一个文件的内容时) ,就进行了编码转换,使用了具体的编码方案(也有一种很特殊的情况,使得在 JVM 内部也需要转换,不过这个是后话) 。因此可以说,所有的编码转换就只发生在边界的地方,JVM 和 OS 的交界处,也就是你的各种输入输出流(或者 Reader,Writer 类)起作用的地方。话头扯到这里就必须接着说 Java 的 IO 系统。尽管看上去混乱繁杂,但是所有的 IO 基本上可以分为两大阵营:面向字符的 Reader 和 Wrtier,以及面向字节的输入输出流。下面我来逐一分解,其实一点也不难。面向字符和面向字节中的所谓“面向”

3、什么,是指这些类在处理输入输出的时候,在哪个意义上保持一致?如果面向字节,那么这类工作要保证系统中的文件二进制内容和读入 JVM内部的二进制内容要一致。不能变换任何 0 和 1 的顺序。因此这是一种非常“忠实于原著”的做法。这种输入输出方式很适合读入视频文件或者音频文件,或者任何不需要做变换的文件内容。而面向字符的 IO 是指希望系统中的文件的字符和读入内存的“字符” (注意和字节的区别)要一致。例如:我们的中文版 Windows XP 系统上有一个 GBK 的文本文件,其中有一个“汉”字,这个字的 GBK 编码是 0xBABA(而 UTF-16 编码是 0x6C49) ,当我们使用面向字符的

4、 IO 把它读入内存并保存在一个 char 型变量中时,我希望 IO 系统不要傻傻的直接把 0xBABA 放到这个 char 型变量中,我甚至都不关心这个 char 型变量具体的二进制内容到底是多少,我只希望这个字符读进来之后仍然是“汉”这个字。从这个意义上也可以看出,面向字符的 IO 类,也就是 Reader 和 Writer 类,实际上隐式的为我们做了编码转换,在输出时,将内存中的 UTF-16 编码字符使用系统默认的编码方式进行了编码,而在输入时,将文件系统中已经编码过的字符使用默认编码方案进行了还原。我两次提到“默认” ,是说 Reader 和 Writer 的聪明也仅此而已了,它们只

5、会使用这个默认的编码来做转换,你不能为一个 Reader 或者 Writer 指定转换时使用的编码。这也意味着,如果你使用中文版 Windows XP 系统,而上面存放了一个 UTF-8 编码的文件,当你使用 Reader 类来读入的时候,它会傻傻的使用GBK 来做转换,转换后的内容当然驴唇不对马嘴!这种笨,有时候其实是一种傻瓜式的功能提供方式,对大多数初级用户(以及不需要跨平台的高级用户)来说反而是件好事。但我们不一样啦,我们都是国家栋梁,肩负着赶英超美的责任,必须师夷长技以治夷,所以我们总还要和 GBK 编码以外的文件打交道。说了上面这些内容,想必聪明的读者已经看出来,所谓编码转换就是一个

6、字符与字节之间的转换,因此 Java 的 IO 系统中能够指定转换编码的地方,也就在字符与字节转换的地方,那就是(InputSteamReader 和OutputStreamWriter)这两个类是字节流和字符流之间的适配器类,因此他们肩负着编码转换的任务简直太自然啦!要注意,实际上也只能在这两类实例化的时候指定编码,是不是很好记呢?下面来写一段小程序,来把“汉”字用我们非常崇拜的 UTF-8 编码写到文件中!tryPrintWriter out=new PrintWriter(new OutputStreamWriter(new FileOutputStream(“c:/utf-8.txt“

7、),“UTF-8“);tryout.write(“汉“);finallyout.close();catch(IOException e)throw new RuntimeException(e);运行之后到 c 盘下去找 utf-8.txt 这个文件,用 UltraEdit 打开,使用 16 进制查看,看到了什么?它的值是 0xE6B189!(这正是“汉”这个字的 UTF-8 编码)3 关于 C/C+语言程序的编码问题介绍3.1 问题引入我们都知道 Java 语言采用的是 Unicode 字符集,字符编码采用的是 UTF-16。因此,在 Java 语言中一个汉字同一个英文字母的地位是等同的,都

8、用 2 个字节存储。在 Java 语言中,char 型数据占 16 位(2 字节) ,取值范围是065535。所以我们可以使用下列语句,即可以把一个汉字赋给一个 char 型变量,例如有下列 Java 程序:char han = 汉;System.out.format(“%x“,(short)han);输出是:6c49反过来用 UTF-16 编码来指定一个字符也可以,像这样:char han = 0x6c49;System.out.println(han);输出是:汉而且在 Java 语言中,我们还可以使用中文来命名变量名、方法名、类名等。而在 C 语言中,char 型数据占 8 位(1 字节

9、) ,取值范围是-128127。一共能表示 256 个字符。按照道理,char 型数据对应的字符集应该是 EASCII 字符集。EASCII 字符集可以勉强显示其他西欧语言。我们先看一个 C 语言程序:#includeint main()char a = -110;char* pa = printf(pa);return 0;按照我们的思维,这个语句打印的应该是一个西欧国家的字符。但是,在中文版的 Windows 系统中,该程序输出的是:这是为什么呢?另外,C 语言是美国人发明的,它开始采用的字符集肯定是 ASCII 字符集或者 EASCII 字符集。但是,我们都知道,C 语言可以输入输出中文

10、字符。这又是为什么?为了解开这些疑惑,我们先来了解下面的知识:3.2 几个相关概念首先要区分几个概念:C/C+源文件的编码指的是 C+源程序文件(.cpp/.h)本身使用什么字符编码(GB18030/UTF-8 等)。C/C+程序的内码是指编译后,C+中的字符串常量都会变成一串字节存放在可执行文件中。这个内码指的就是在可执行文件中,字符串以什么编码进行存放。这里的字符串常量指的是窄字符(char)而非宽字符(wchar_t)。宽字符通常是以 Unicode(VC 使用 UTF-16BE,gcc 使用 UTF-32BE)存放。运行环境编码指的是执行程序时,操作系统或终端所使用的编码。程序中输出的

11、字符最终要转换为运行环境编码才能正确显示,否则就会出现乱码。3.3 各种环境下通常使用的编码3.3.1 C/C+源文件的编码通常在简体中文 Windows 环境下,各种编辑器(包括 Visual Studio)新建文件的缺省编码都是 GB18030,所以不特别指定的话,Windows 环境下 C+源文件的编码通常为 GB18030。而在 Linux 环境下,最常使用,也是推荐使用的是 UTF-8 编码。3.3.2 C/C+程序的内码一般来说,我们常用的简体中文版 VC 所使用的内码是 GB18030,而gcc/g+使用的内码缺省是 utf-8,但可以通过-fexec-charset 参数进行修

12、改。Note 可以通过在程序中打印字符串每个字节十六进制形式来判断程序所使用的内码。3.3.3 运行环境编码但是我们都知道这样一个事实,我们用 C 语言编写程序时,可以输出中文。那么这又是为什么呢?我们常用的简体中文版 Windows 的环境编码是 GB18030,而 Linux 下最常用的环境编码是 UTF-8。3.3.4 这几个编码之间的关系源程序需要由编译器编译为目标文件,目标文件运行后输出信息到终端,因此这几个编码之间存在一些的关联:编译器需要正确识别源文件的编码,把源文件编译为目标文件,并把源文件中的以源文件编码的字符串转换为以程序内码编制的字符串保存在目标文件中。Note 当源文件

13、的字符编码与程序内码都是 UTF-8 时(gcc 的缺省情况),gcc似乎并不会对源文件中的字符编码进行转换,而是直接把字符串原样存放到目标文件中,在这种情况下,源程序中的 GB18030 编码的字符串在输出时仍然为GB18030 编码。但如果在其它源文件字符编码的实际值与编译选项不同时,会在编译时报无法从 XXX 转换到 UTF-8 的错,因此还不清楚为什么两个编码都是 UTF-8 时,GB18030 编码的源文件能通过编译。C+标准库需要正确识别终端的运行环境编码,并把程序的输出转换为运行环境所使用的编码,以便正确显示。在这过程中,如果有一个环节出现问题,就会导致程序的输出发生异常,产生乱

14、码或其它更严重的后果。3.4 源文件应该采用什么编码?3.4.1 编译器对不同源文件编码的支持一样吗?gcc/vc 各版本对 C+源文件编码有不同的处理:gcc (v4.3.2 20081105):支持 UTF-8 编码的源文件,UTF-8 编码的源文件不能有 BOM。开始支持带 BOM 的 UTF-8 文件。vc2003: 支持 UTF-8 编码的源文件,UTF-8 编码的源文件可以有 BOM,也可以没有。vc2005+: 如果源文件使用 UTF-8 编码的话,必须有 BOM。Note gcc 提供了-finput-charset 参数可以指定源文件的字符编码,但由于标准头文件都是 asci

15、i 编码的,因此如果要引用标准头文件的话,源代码的编码必须兼容 ascii。而 vc 未能找到类似的选项。3.4.2 源文件应该采用什么编码?很多文章都推荐 C/C+代码中只使用 ascii 字符,如果有非 ascii 字符可以用xHH 或uXXXX 表示。注释中建议使用 utf-8 编码。也可以使用 gettext 把非ascii 字符串放到单独的语言文件中,而在源代码中只保留 ascii 字符。在实践中,由于xHH 或uXXXX 等方式很不直观,容易出错且不易发现,而未必所有程序都需要支持多语言,因此未必想引入 gettext 或类似的解决方案。在这样的情况下,大家都习惯在源程序文件中直接

16、写入中文等非 ascii 字符,这就需要选择一种至少能被 gcc 和 vc 接受的文件编码。本来,Unicode 是解决多语言问题的最好选择,而 UTF-8 由于与 ASCII 兼容,也是最通用的 Unicode编码方式,但从上面的资料中可见,如果用 UTF-8 的话,gcc(至少是低版本)不允许有 BOM,而 vc2005 以上要求必须有 BOM,因此同一个文件无法在 gcc及 vc 下通过编译,UTF-8 似乎不是一个好的选择。但如果使用 gcc 比较高的版本(4.4.0 以上?),使用带 BOM 的 UTF-8 编码文件应该也是可行的。考虑到目前现状,我们一般都在简体中文 Windows 下工作,源文件中使用 GB18030=编码似乎是一个比较现实的选择。在 vc 下可以直接编译,而在 gcc 下也可以通过增加编译选项-finput-charset=gb18030 予以支持。而且根据维基百科中 GB18030 的词条内容,GB18030 is a superset of ASCII and can rep

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 行业资料 > 其它行业文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号