关于编码的思考(unicode字符集和utf-8 utf-16)

1.unicode    字符集的前世今生

     你可能有点疑惑,文章标题是说编码的问题,可是和字符集有什么关系? 别急,先想象一下有两个人,他们使用书信来交流。在 他们交流的过程中,必须将自己要表达的意思用相互都了解的规则转化为文字以让对方了解自己的想法。在写信中这个相互都了解的规则就是我们要说的字符集。

       知道了字符集是什么,下面说下字符集有什么用:它将现实中的字符映射为逻辑中的数字(就是给定一个规则让一个数字对应一个字符)。那么有几种字符集呢:简单来说可以分为3类:1.ASCII字符集 2 .ANSI字符集 3.Unicode字符集 (这是我们今天讨论的主角)。

    有了unicode字符集,我们可以把字符映射为数字了,这个数字就叫做码点(codePoint),可是在unicode字符集内部是如何进行映射的? 在其内部,将码点映射到了0 - 16 号 17个平面,每个平面有2^16个字符。所以用使用了21位2进制数字来表示了所有的字符。其中平面0的字符比较特殊,它兼容ASCII字符集。

2.utf - 8 编码方式, utf - 16 编码方式

     现在我们已经知道如何将字符变为码点了,下面我们看如何将码点转为为物理上的表示,也就是说码点如何用码元(code unit) 表示。回到写信的例子,当我们想表达一个概念的时候,可能要用一个或多个字来表示。那么对应一个码点来说,也需要一个或多个码元来表示。

    在unicode 中由码元到码点的编码方式主要有2种 :utf-8(变长编码) , utf-16(初始为不可变长编码)。

     UTF-16 具体定义了 Unicode 字符在计算机中存取方法。UTF-16 用两个字节来表示 Unicode 转化格式,这个是定长的表示方法,大多数常用字符都可以用两个字节表示,两个字节是 16 个 bit,所以叫 UTF-16。UTF-16 表示字符非常方便,每两个字节表示一个字符,这个在字符串操作时就大大简化了操作,这也是 Java 以 UTF-16 作为内存的字符存储格式的一个很重要的原因。 UTF-16的码元是16位的。

    UTF-16 统一采用两个字节表示一个字符,虽然在表示上非常简单方便,但是也有其缺点,有很大一部分字符用一个字节就可以表示的现在要两个字节表示,存储空间放大了一倍,在现在的网络带宽还非常有限的今天,这样会增大网络传输的流量,而且也没必要。而 UTF-8 采用了一种变长技术,每个编码区域有不同的字码长度。不同类型的字符可以是由 1~3 个字节组成。UTF-8的码元是8位的。UTF-8 有以下编码规则:

  1. 如果一个字节,最高位(第 8 位)为 0,表示这是一个 ASCII 字符(00 - 7F)。可见,所有 ASCII 编码已经是 UTF-8 了。
  2. 如果一个字节,以 11 开头,连续的 1 的个数暗示这个字符的字节数,例如:110xxxxx 代表它是双字节 UTF-8 字符的首字节。
  3. 如果一个字节,以 10 开始,表示它不是首字节,需要向前查找才能得到当前字符的首字节。

3.编码方式与Java的关系

现在我们来思考2个很普遍的问题:

1.java中能否用一个char表示所有字符?

要回答这个问题,需要再明确一个概念,外码内码

内码是程序内部使用的字符编码,特别是某种语言实现其char或String类型在内存里用的内部编码;
外码是程序与外部交互时外部使用的字符编码。“外部”相对“内部”而言;不是char或String在内存里用的内部编码的地方都可以认为是“外部”。例如,外部可以是序列化之后的char或String,或者外部的文件、命令行参数之类的。

Java语言规范规定,Java的char类型是UTF-16的code unit,也就是一定是16位(2字节);

 

char, whose values are 16-bit unsigned integers representing UTF-16 code units ( §3.1).

 

字符串是UTF-16 code unit的序列:

 

The Java programming language represents text in sequences of 16-bit code units, using the UTF-16 encoding.

这样,Java规定了字符的内码要用UTF-16编码。或者至少要让用户无法感知到String内部采用了非UTF-16的编码。

所以,在java中char的物理实现方式是utf - 16,对于大多数的字符来说,都可以用一个char来表示。但是对于扩展后的字符来说一个char就不够了。

 

2.既然一个char长为2字节,但是为什么如new String("字").getBytes().length,返回为3呢?

这里的原因主要在于外码,在String中长度为2个字节,但是用getBytes()后,转为了外码使用的utf-8编码,所以返回了3.

 

另外说下java中对于2种编码方式的选择。

Java标准库实现的对char与String的序列化规定使用UTF-8作为外码。Java的Class文件中的字符串常量与符号名字也都规定用UTF-8编码。这大概是当时设计者为了平衡运行时的时间效率(采用定长编码的UTF-16)与外部存储的空间效率(采用变长的UTF-8编码)而做的取舍。

以及java中的相关的api:

1.String.charAt(int i) 返回指定位置的码元

2.Stirng.codePointAt()  返回指定位置处的码点

3.String.length() 返回String中码元的数量

4.String.codePointCount(int start, int end) 返回指定范围内码点的数量

length 方法将返回采用 UTF-16 编码表示的给定字符串所需要的代码单元数量。例如:
String greeting = "Hello";
int n = greeting.length。; // is 5 .
要想得到实际的长度,即码点数量,可以调用:
int cpCount = greeting.codePointCount(0, greeting.length());
调用 s.charAt(n) 将返回位置 n 的代码单元,n 介于 0 ~ s.length()-l 之间。例如:
char first = greeting.charAt(0); // first is 'H'
char last = greeting.charAt(4); // last is ’o’
要想得到第 i 个码点,应该使用下列语句
int index = greeting.offsetByCodePoints(0,i);
int cp = greeting.codePointAt(index); 

codePoints 方法, 它会生成一个 int 值的“ 流”,
每个 int 值对应一个码点。可以将它转换为一个数组,再完成遍历。
int[] codePoints = str.codePoints.toArray;
反之, 要把一个码点数组转换为一个字符串, 
String str = new String(codePoints, 0, codePoints.length) ;

### 回答1: Unicode字符集是一种包含了世界上几乎所有字符的编码标准,包括了各种语言的字母、符号、标点、数字等等。它为每个字符分配了一个唯一的数字编号,这个编号被称为Unicode码点。 UTF-8编码是一种将Unicode字符集中的码点转换成字节序列的方法。它是一种可变长度的编码方式,使用1到4个字节来表示不同的字符,其中ASCII字符只需要1个字节,而中文等非ASCII字符则需要2到3个字节。UTF-8编码具有向后兼容性,可以表示Unicode字符集中的所有字符,因此被广泛应用于互联网和计算机系统中。 ### 回答2: Unicode字符集是一种用于描述世界各种语言的字符集合的标准规范。Unicode字符集包含了现今世界上大部分语言所使用的字符,包括字母、数字、符号、标点符号以及各种特殊字符。Unicode字符集采用唯一的数字编号来表示每个字符,这些数字被称为“码位”或“码点”。 UTF-8编码是一种针对Unicode字符集编码方案,可以将Unicode字符集中的每个字符以不同的排列组合方式表示为一组字节,使得这些字符能够在计算机中被存储和传输。UTF-8编码采用可变长度的编码方式,对于不同范围内的字符,采用不同长度的字节表示。例如,对于ASCII字符集中的字符,UTF-8编码只需要用一个字节表示,而对于其他语言的字符,则需要用两个、三个或四个字节来表示。 相比于其他编码方案,UTF-8编码具有许多优势。首先,UTF-8编码能够支持所有的Unicode字符,包括汉字、日语假名、俄文字母和阿拉伯语字母等。其次,UTF-8编码具有良好的兼容性,能够在不同的操作系统、浏览器和编辑器中使用。最后,UTF-8编码还具有节省空间的优势,因为它可以根据字符所在范围的不同动态调整字节的长度,有效地减少字节数,从而节省存储空间和带宽。 总之,Unicode字符集UTF-8编码是现今计算机技术中使用最广泛的字符集编码方案。他们为计算机在处理不同语言和字符类型的文本数据时提供了可靠的工具和标准,大大提高了计算机的文本应用能力。 ### 回答3: Unicode是全球字符集,它为世界上几乎所有的符号分配了唯一的标识符。由于计算机只能理解数字,Unicode为每个字符分配了一个唯一的数字,从而使计算机能够正确地显示、存储和处理文本。Unicode字符集由超过128,000个字符组成,其中包括各种字母、数字、标点符号、符号和特殊字符。 UTF-8是一种广泛使用的Unicode编码,它使用1到4个字节来表示每个字符。UTF-8编码使用变长编码方法,这意味着不同字符使用不同数量的字节来表示。对于较小的字符,UTF-8只需要1个字节,而对于较大的字符,UTF-8需要多个字节。这使得UTF-8成为比其他Unicode编码更节省空间和更灵活的编码方式。 在计算机上,文本通常被存储为字节序列。使用Unicode字符集UTF-8编码可以确保多种语言的文本能够正确存储和处理,从而实现跨语言的通信和交流。今天,大多数操作系统和应用程序都支持UnicodeUTF-8编码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值