20200227 java中的字符,字节和编码
Posted 流星<。)#)))≦
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了20200227 java中的字符,字节和编码相关的知识,希望对你有一定的参考价值。
java中的字符,字节和编码
字符与编码的发展
从计算机对多国语言的支持角度看,大致可以分为三个阶段:
系统内码 | 说明 | 系统 | |
---|---|---|---|
阶段一 | ASCII | 计算机刚开始只支持英语,其它语言不能够在计算机上存储和显示。 | 英文 DOS |
阶段二 | ANSI编码 (本地化) | 为使计算机支持更多语言,通常使用 0x80~0xFF 范围的 2 个字节来表示 1 个字符。比如:汉字 ‘中’ 在中文操作系统中,使用 [0xD6,0xD0] 这两个字节存储。 不同的国家和地区制定了不同的标准,由此产生了 GB2312, BIG5, JIS 等各自的编码标准。这些使用 2 个字节来代表一个字符的各种汉字延伸编码方式,称为 ANSI 编码。在简体中文系统下,ANSI 编码代表 GB2312 编码,在日文操作系统下,ANSI 编码代表 JIS 编码。 不同 ANSI 编码之间互不兼容,当信息在国际间交流时,无法将属于两种语言的文字,存储在同一段 ANSI 编码的文本中。 | 中文 DOS,中文 Windows 95/98,日文 Windows 95/98 |
阶段三 | UNICODE (国际化) | 为了使国际间信息交流更加方便,国际组织制定了 UNICODE 字符集,为各种语言中的每一个字符设定了统一并且唯一的数字编号,以满足跨语言、跨平台进行文本转换、处理的要求。 | Windows NT/2000/XP,Linux,Java |
字符串在内存中的存放方法:
- 在 ASCII 阶段,单字节字符串使用一个字节存放一个字符(SBCS)。比如,”Bob123” 在内存中为7个字节
- 在使用 ANSI 编码支持多种语言阶段,每个字符使用一个字节或多个字节来表示(MBCS),因此,这种方式存放的字符也被称作多字节字符。比如,”中文123” 在中文 Windows 95 内存中为7个字节,每个汉字占2个字节,每个英文和数字字符占1个字节
- 在 UNICODE 被采用之后,计算机存放字符串时,改为存放每个字符在 UNICODE 字符集中的序号。目前计算机一般使用 2 个字节(16 位)来存放一个序号(DBCS),因此,这种方式存放的字符也被称作宽字节字符。比如,字符串 “中文123” 在 Windows 2000 下,内存中实际存放的是 5 个序号,一共占 10 个字节。
Ascii及中国的编码
Ascii(American Standard Code for Information Interchange),美国信息互换标准代码,官方的ASCII码表。
Ascii为八位一个字节,一共可以组合出256(2的8次方)种不同的状态。
一开始美国人把其中的编号从0开始的32种状态分别规定了特殊的用途,一但终端、打印机遇上约定好的这些字节被传过来时,就要做一些约定的动作。遇上00x10, 终端就换行,例好遇上0x1b, 打印机就打印反白的字,或者终端就用彩色显示字母。这些0x20以下的字节状态称为”控制码”。
接着把所有的空格、标点符号、数字、大小写字母分别用连续的字节状态表示,一直编到了第127号,这样计算机就可以用不同字节来存储英语的文字了。
后来,就像建造巴比伦塔一样,世界各地的都开始使用计算机,但是很多国家用的不是英文,他们的字母里有许多是ASCII里没有的。他们决定采用127号之后的空位来表示这些新的字母、符号,还加入了很多画表格时需要用下到的横线、竖线、交叉等形状,一直把序号编到了最后一个状态255。从128到255这一页的字符集被称”扩展字符集”。
我国创造了两个字节编码的“GB2312”以及之后的同样是两个字节的“GBK”。之后“GBK”扩展为“GB18030”,这些编码标准被通称为 “DBCS”(Double Byte Charecter Set 双字节字符集)。
DBSC系列的标准的最大特点是,最大的特点是两字节长的汉字字符和一字节长的英文字符并存于同一套编码方案里,如果一个字节小于127那么按照Ascii的编码,如果大于127那么其和后面的字符组成一个汉字字符。
然后各国也是按照自己的需求弄了一套自己可用的编码。很愉快大家都能用了,接着发现不对啊,各个国家之间电脑需要交流,你的资源到我这里编程乱码,我的资源你也用不了。
于是, ISO (国际标谁化组织)决定着手解决这个问题。他们采用的方法很简单:废了所有的地区性编码方案,重新搞一个包括了地球上所有文化、所有字母和符号的编码。他们打算叫它”Universal Multiple-Octet Coded Character Set”,简称 UCS, 俗称 “UNICODE”。
对于ascii里的那些“半角”字符(即前面排到128个字符),UNICODE 包持其原编码不变,只是将其长度由原来的8位扩展为16位,而其他文化和语言的字符则全部重新统一编码。由于”半角”英文符号只需要用到低8位,所以其高8位永远是0,因此这种大气的方案在保存英文文本时会多浪费一倍的空间。
字符,字节,字符串
理解编码的关键,是要把字符的概念和字节的概念理解准确。这两个概念容易混淆,我们在此做一下区分:
概念描述 | 举例 | |
---|---|---|
字符 | 人们使用的记号,抽象意义上的一个符号。 | ‘1’, ‘中’, ‘a’, ‘$’, ‘¥’, …… |
字节 | 计算机中存储数据的单元,一个8位的二进制数,是一个很具体的存储空间。 | 0x01, 0x45, 0xFA, …… |
ANSI 字符串 | 在内存中,如果“字符”是以 ANSI 编码形式存在的,一个字符可能使用一个字节或多个字节来表示,那么我们称这种字符串为 ANSI 字符串或者多字节字符串。 | “中文123” (占7字节) |
UNICODE 字符串 | 在内存中,如果“字符”是以在 UNICODE 中的序号存在的,那么我们称这种字符串为 UNICODE 字符串或者宽字节字符串。 | L”中文123” (占10字节) |
由于不同 ANSI 编码所规定的标准是不相同的,因此,对于一个给定的多字节字符串,我们必须知道它采用的是哪一种编码规则,才能够知道它包含了哪些“字符”。而对于UNICODE 字符串来说,不管在什么环境下,它所代表的“字符”内容总是不变的。
字符集与编码
各个国家和地区所制定的不同 ANSI 编码标准中,都只规定了各自语言所需的“字符”。比如:汉字标准(GB2312)中没有规定韩国语字符怎样存储。这些 ANSI 编码标准所规定的内容包含两层含义:
- 使用哪些字符。也就是说哪些汉字,字母和符号会被收入标准中。所包含“字符”的集合就叫做“字符集”。
- 规定每个“字符”分别用一个字节还是多个字节存储,用哪些字节来存储,这个规定就叫做“编码”。
各个国家和地区在制定编码标准的时候,“字符的集合”和“编码”一般都是同时制定的。因此,平常我们所说的“字符集”,比如:GB2312, GBK, JIS 等,除了有“字符的集合”这层含义外,同时也包含了“编码”的含义。
“UNICODE 字符集”包含了各种语言中使用到的所有“字符”。用来给 UNICODE 字符集编码的标准有很多种,比如:UTF-8, UTF-7, UTF-16, UnicodeLittle, UnicodeBig 等。
常用的编码简介
简单介绍一下常用的编码规则,为后边的章节做一个准备。在这里,我们根据编码规则的特点,把所有的编码分成三类:
分类 | 编码标准 | 说明 |
---|---|---|
单字节字符编码 | ISO-8859-1 | 最简单的编码规则,每一个字节直接作为一个 UNICODE 字符。比如,[0xD6, 0xD0] 这两个字节,通过 iso-8859-1 转化为字符串时,将直接得到 [0x00D6, 0x00D0] 两个 UNICODE 字符,即 “?D”。 反之,将 UNICODE 字符串通过 iso-8859-1 转化为字节串时,只能正常转化 0~255 范围的字符。 |
ANSI 编码 | GB2312, BIG5, Shift_JIS, ISO-8859-2 …… | 把 UNICODE 字符串通过 ANSI 编码转化为“字节串”时,根据各自编码的规定,一个 UNICODE 字符可能转化成一个字节或多个字节。 反之,将字节串转化成字符串时,也可能多个字节转化成一个字符。比如,[0xD6, 0xD0] 这两个字节,通过 GB2312 转化为字符串时,将得到 [0x4E2D] 一个字符,即 ‘中’ 字。 “ANSI 编码”的特点: 1. 这些“ANSI 编码标准”都只能处理各自语言范围之内的 UNICODE 字符。 2. “UNICODE 字符”与“转换出来的字节”之间的关系是人为规定的。 |
UNICODE 编码 | UTF-8, UTF-16, UnicodeBig …… | 与“ANSI 编码”类似的,把字符串通过 UNICODE 编码转化成“字节串”时,一个 UNICODE 字符可能转化成一个字节或多个字节。 与“ANSI 编码”不同的是: 1. 这些“UNICODE 编码”能够处理所有的 UNICODE 字符。 2. “UNICODE 字符”与“转换出来的字节”之间是可以通过计算得到的。 |
我们实际上没有必要去深究每一种编码具体把某一个字符编码成了哪几个字节,我们只需要知道“编码”的概念就是把“字符”转化成“字节”就可以了。对于“UNICODE 编码”,由于它们是可以通过计算得到的,因此,在特殊的场合,我们可以去了解某一种“UNICODE 编码”是怎样的规则。
Unicode及UTF
UNICODE 是用两个字节来表示为一个字符,他总共可以组合出65535不同的字符,这大概已经可以覆盖世界上所有文化的符号。UNICODE 如何在网络上传输也是一个必须考虑的问题,于是面向传输的众多 UTF(UCS Transfer Format)标准出现了,顾名思义,UTF8就是每次8个位传输数据,而UTF16就是每次16个位,只不过为了传输时的可靠性,从UNICODE到UTF时并不是直接的对应,而是要过一些算法和规则来转换。而且网络传输字符编码也涉及到大端小端的问题。
Java中的字符与字节
类型或操作 | Java |
---|---|
字符 | char |
字节 | byte |
ANSI 字符串 | byte[] |
UNICODE 字符串 | String |
字节串→字符串 | string = new String(bytes, “encoding”) |
字符串→字节串 | bytes = string.getBytes(“encoding”) |
java中的编码
前面说了,java使用到编码是UNICODE。怎么具体“体会到”这种编码呢?我们可以用java中的转义符 。
一、我们直接使用“”来转化数字为字符的话,后面的数字应为八进制。
而且只能转化一个字节大小,即255个字符,如下:
- 八进制转义序列:?+ 八进制数;范围’ 00’~’377’(对应十进制0~255)