位、字节、字符、编码的区别及编码问题解析

一、定义

1.1、位

        数据存储的最小单元,每个二进制数字0或1就是1个位(bit)

1.2、字节

        1个字节(byte)由8个位(bit)构成

        1byte = 8 bit

        1KB = 1024 B(字节)

1.3、字符

        '1','子','¥','#' 都表示一个字符。

        在Java 语言中,字符用char 表示。

1.4、字符集

        字面意思就是一些字符的集合,比如多少汉字的一个集合,就是字符集。

        UNICODE 字符集 :包含了各种语言中使用到的所有“字符 ”。用来给UNICODE 字符集编码的标准有很多种,比如:UTF-8,UTF-7,UTF-16,UnicodeLittlle,UnicodeBig 等

1.5、编码

       字符和字节的映射关系,一个字符用多少个字节表示,用那些字节来表示。对应着字符集 和 字节的映射关系。

二、为什么会产生编码问题

2.1 字符和编码的发展

        从计算机对多国语言的支持角度看,大致可以分为三个阶段:

 系统内码说明系统
阶段一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" 在内存中为:

42 6F 62 31 32 33 00
__ __ __ __ __ __ __

B  o  b  1  2  3  \0

在使用 ANSI 编码支持多种语言阶段,每个字符使用一个字节或多个字节来表示(MBCS),因此,这种方式存放的字符也被称作多字节字符。比如,"中文123" 在中文 Windows 95 内存中为7个字节,每个汉字占2个字节,每个英文和数字字符占1个字节:

D6D0  CEC4  31  32  33  00
____  ____  __  __  __  __

中    文    1   2   3   \0

在 UNICODE 被采用之后,计算机存放字符串时,改为存放每个字符在 UNICODE 字符集中的序号。目前计算机一般使用 2 个字节(16 位)来存放一个序号(DBCS),因此,这种方式存放的字符也被称作宽字节字符。比如,字符串 "中文123" 在 Windows 2000 下,内存中实际存放的是 5 个序号

2D 4E  87 65  31 00  32 00  33 00  00 00
_____  _____  _____  _____  _____  _____

中     文     1      2      3      \0

一共占 10 个字节。

2.2 常用的编码简介

我们根据编码规则的特点,把所有的编码分成三类:

分类编码标准说明
单字节字符编码ISO-8859-1最简单的编码规则,每一个字节直接作为一个 UNICODE 字符。比如,[0xD6, 0xD0] 这两个字节,通过 iso-8859-1 转化为字符串时,将直接得到 [0x00D6, 0x00D0] 两个 UNICODE 字符,即 "ÖÐ"。

反之,将 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 字符”与“转换出来的字节”之间是可以通过计算得到的。

2.3 程序中的字符与字节

类型与操作Java
字符char
字节byte
ANSI 字符串byte[]
UNICODE 字符串String
字节串 --> 字符串string = new String(bytes,"encoding")
字符串 --> 字节串bytes = string.getBytes("encoding")

Java 中的char 代表一个 UNICODE 字符(宽字节字符)

2.4 编码问题的产生和解决

        在将“字节串”转为“UNICODE 字符串”时,比如在读取文本文件时,或者通过网络传输文本时,容易将 “字节串” 简单的作为“单字节字符串”,采用每“一个字节” 就是一个字符的方法进行转化。

         而实际上,在非英文的环境下,应该“字节串”作为ANSI 字符串,采用适当的编码来得到UNICODE 字符串,有可能“多个字节”才能得到“一个字符”。 

         我们的系统在进行交互时,前端与后台的交互,跨平台之间数据传输,会因为平台与平台之间的编码不同,传输方式的不同导致解码不一致的情况。这个时候,我们可以先全部通过iso-8859-1 方式统一将字节 转成 字符,这个是一对一的转化,然后将它转成指定的某种编码即可。

三、其他

        iso-8859-1 只是单字节字符集中最简单的一种,也就是“字节编号”与“UNICODE 字符编号”一致的那种编码规则。当我们要把一个“字节串”转化成“字符串”,而又不知道它是哪一种 ANSI 编码时,先暂时地把“每一个字节”作为“一个字符”进行转化,不会造成信息丢失。然后再使用 bytes = string.getBytes("iso-8859-1") 的方法可恢复到原始的字节串。


参考

字符,字节和编码(推荐)

Java常见的乱码解决方式(推荐)

位(bit)、字节(byte)、字符、编码之间的关系

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值