ASCII、Unicode和UTF8

ascii, unicode, utf8

ASCII

  • ascii码使用指定的7位或8位二进制数组合表示128或256种可能的字符,标准ASCII码也叫基础ASCII码,使用7位二进制数(剩下的1位二进制为0)来表示所有的大写和小写字母,数字0到9、标点符号,以及再美式英语中使用的特殊字符,其中:

    • 0 ~ 31及127(共33个)是控制字符或通信专用字符(其余为可显示字符),如控制字符:LF(换行), CR(回车);通信专用字符:SOH(文头)、ACK(确认)等;ASCII值为8、9、10和13分别转换为退格、制表、换行和回车,它们并没有特定的图形显示,但会依不同的应用程序,而对文本显示不同的影响。
    • 32 ~ 126(共95个)是字符(32是空格),其中48~57位0到9十个阿拉伯数字,65 ~ 90为26个大写英文字母,97 ~ 122为26个小写英文字母,其余为一些标点符号、运算符号等。
  • 同时还要注意,在标准ASCII中,其中最高位(b7)用作奇偶校验。所谓奇偶校验,是指在代码传送过程中用来校验是否出现错误的一种方法,一般分为奇校验和偶校验两种。

    • 奇校验规定:正确的代码一个字节中1的个数必须是1,若非技术,则在最高位b7添1.
    • 偶校验规定:正确的代码一个字节中1的个数必须是偶数,若非偶数,则在最高位(b7)添1.
  • 后128个称为扩展ASCII码。许多基于x86的系统都支持使用扩展(或“高”ASCII)。扩展ASCII码允许将每个字符的第8位用于确定附加的128个特殊符号字符、外来语字母和图形符号

Unicode

  • Unicode是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。Unicode用数字0-0x10FFFF来映射这些字符,最多可以容纳1114112个字符,或者说有1114112个码位。码位就是可以分配给字符的数字。UTF-8、UTF-16、UTF-32都是将数字转换到程序数据的编码方案。

  • Unicode 源于一个很简单的想法:将全世界所有的字符包含在一个集合里,计算机只要支持这一个字符集,就能显示所有的字符,再也不会有乱码了。

  • 它从 0 开始,为每个符号指定一个编号,这叫做”码点”(code point)。比如,码点 0 的符号就是 null(表示所有二进制位都是 0)。
  • 这么多符号,Unicode 不是一次性定义的,而是分区定义。每个区可以存放 65536 个(2^16)字符,称为一个平面(plane)。目前,一共有 17 个平面,也就是说,整个 Unicode 字符集的大小现在是 2^21。
  • 最前面的 65536 个字符位,称为基本平面(缩写 BMP),它的码点范围是从 0 一直到 2^16-1,写成 16 进制就是从 U+0000 到 U+FFFF。所有最常见的字符都放在这个平面,这是 Unicode 最先定义和公布的一个平面。
  • 剩下的字符都放在辅助平面(缩写 SMP),码点范围从 U+010000 一直到 U+10FFFF。
  • Unicode 只规定了每个字符的码点,到底用什么样的字节序表示这个码点,就涉及到编码方法。
  • Unicode 编码方案
  • 之前提到,Unicode 没有规定字符对应的二进制码如何存储。以汉字“汉”为例,它的 Unicode 码点是 0x6c49,对应的二进制数是 110110001001001,二进制数有 15 位,这也就说明了它至少需要 2 个字节来表示。可以想象,在 Unicode 字典中往后的字符可能就需要 3 个字节或者 4 个字节,甚至更多字节来表示了。
  • 这就导致了一些问题,计算机怎么知道你这个 2 个字节表示的是一个字符,而不是分别表示两个字符呢?这里我们可能会想到,那就取个最大的,假如 Unicode 中最大的字符用 4 字节就可以表示了,那么我们就将所有的字符都用 4 个字节来表示,不够的就往前面补 0。这样确实可以解决编码问题,但是却造成了空间的极大浪费,如果是一个英文文档,那文件大小就大出了 3 倍,这显然是无法接受的。
  • 于是,为了较好的解决 Unicode 的编码问题, UTF-8 和 UTF-16 两种当前比较流行的编码方式诞生了。当然还有一个 UTF-32 的编码方式,也就是上述那种定长编码,字符统一使用 4 个字节,虽然看似方便,但是却不如另外两种编码方式使用广泛。

UTF8

UTF-8 是一个非常惊艳的编码方式,漂亮的实现了对 ASCII 码的向后兼容,以保证 Unicode 可以被大众接受。

  • UTF-8 是目前互联网上使用最广泛的一种 Unicode 编码方式,它的最大特点就是可变长。它可以使用 1 - 4 个字节表示一个字符,根据字符的不同变换长度。编码规则如下:
  • 1.对于单个字节的字符,第一位设为 0,后面的 7 位对应这个字符的 Unicode 码点。因此,对于英文中的 0 - 127 号字符,与 ASCII 码完全相同。这意味着 ASCII 码那个年代的文档用 UTF-8 编码打开完全没有问题。
  • 2.对于需要使用 N 个字节来表示的字符(N > 1),第一个字节的前 N 位都设为 1,第 N + 1 位设为 0,剩余的 N - 1 个字节的前两位都设位 10,剩下的二进制位则使用这个字符的 Unicode 码点来填充。

编码规则如下:

Unicode 十六进制码点范围 UTF-8 二进制
0000 0000 - 0000 007F 0xxxxxxx
0000 0080 - 0000 07FF 110xxxxx 10xxxxxx
0000 0800 - 0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
0001 0000 - 0010 FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
  • 根据上面编码规则对照表,进行 UTF-8 编码和解码就简单多了。下面以汉字“汉”为利,具体说明如何进行 UTF-8 编码和解码。

  • “汉”的 Unicode 码点是 0x6c49(110 1100 0100 1001),通过上面的对照表可以发现,0x0000 6c49 位于第三行的范围,那么得出其格式为 1110xxxx 10xxxxxx 10xxxxxx。接着,从“汉”的二进制数最后一位开始,从后向前依次填充对应格式中的 x,多出的 x 用 0 补上。这样,就得到了“汉”的 UTF-8 编码为 11100110 10110001 10001001,转换成十六进制就是 0xE6 0xB7 0x89。

  • 解码的过程也十分简单:如果一个字节的第一位是 0 ,则说明这个字节对应一个字符;如果一个字节的第一位 1,那么连续有多少个 1,就表示该字符占用多少个字节。


每日一算

描述

在数组中找到 2 个数之和等于给定值的数字,结果返回 2 个数字在数组中的下标

解题思路

利用map的特性,遍历数组预算计算出和给定值的差值,也就是目标元素,若值已经在map中,说明已找到,若没有,则把当前元素以 值=>下标 的形式存到map中

代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
func twoSum(arr []int, target int)[]int{

  var m = map[int]int{}

  for i := 0; i < len(arr); i++ {

    another := target - arr[i]

    if _, ok := m[another]; ok == true {

      return []int{m[another], i}

    }else{

      m[arr[i]] = i

    }

  }
  
  return []int{-1, -1}
}
皖ICP备20014602号
Built with Hugo
Theme Stack designed by Jimmy