字符串和编码

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了字符串和编码相关的知识,希望对你有一定的参考价值。

字符串和编码

标签(空格分隔): Python


1、历史

1.1 字符串

字符串:是一种数据类型,但是字符串比较特殊的还有一个就是编码问题。

1.2 bit和byte

bit是比特,byte是字节

\\[8 bit = 1 byte \\]

\\[1024 byte = 1 KB \\]

因为计算机只能处理数字,要处理文本,就必须把文本装换成数字才能处理,最早的计算机载机设计时采用\\(8\\)\\(bit\\)作为一个字节,所以,一个字节能表示的最大整数就是\\(255\\),其基本单位是字节,所以需要表示更大的数据的时候就需要两个字节,也就是\\(65535\\),4个字节的话表示的最大整数是\\(4294967295\\)。这个时候就有小精灵鬼提出疑问了,我记得C里面int是四个字节,但是最大能表示的数据大概是\\(21\\)亿呀,这个机组有讲第一位作为标识符,有正负标准,所以最大是\\(21\\)亿,负数最大是负\\(21\\)亿。(应该是这样表达的吧? 提前说了是负数的话 大指的是单纯的数据大小)

  • 存储和网速的单位,无论是B还是b,代表的都是Byte
  • 带宽的单位,无论是B还是b,代表的都是比特bit

但是我们在实际应用中更偏向于第一种计量单位,所以办完宽带之后咱们总感觉网速没有那么快,实际上的网速都是\\(\\frac{1}{8}\\)

1.3 各种奇葩编码

由于计算机是美国人发明的,因此我们了解的ASCII编码只有\\(127\\)个字符被收录进去,也就是大小写字母、数字、符号。

但是如果要处理中文的话是远远不够的,《现代汉语常用字表1988年版》就有3500个汉字而且不能和ASCII冲突,并且根据上面说的最小计量单位为byte的话,我们至少需要两个字节,所以中国制定了GB2313编码,用来将中文编入计算机。

但是世界上有很多语言,各国都以这种方法编码的话,机会不可避免的产生冲突,结果就是在多语言混合文本中显示出来会有乱码的情况(学过C的都应该见过 锟斤拷 烫烫烫, 俗称 手持两把锟斤拷 口中直呼烫烫烫)。详情链接

由此Unicode字符集应运而生,他将所有的语言统一到一套编码里面,这样就不会有乱码问题了。其中最常见的是UCS-16编码,用两个字节表示一个字符(如果要用到非常偏僻的字符,就需要4个字节)。现代操作系统和大多数编程语言都直接支持UnicodeASCII用的是一个字节,Unicode一般情况下是两个字节,特别生僻的词会用到四个字节。

  • ASCII中字符A的编码是十进制的65,二进制的0100 0001
  • Unicode中字符A的二进制编码是0000 0000 0100 0001

由上可得:如果统一为Unicode编码的话 会造成很大的内存空间浪费(以前计算机内存很小程序要精打细算,魂斗罗128k,需要实现那么多的剧情和场景,这一块可以联系享元设计模式一块看),这样的话就需要新的解决方法了。

1.3 解决方案

新的风暴已经出现,怎么能够停滞不前。新的方案出来了也就是门外汉也听过的UTF-8编码(希望你们可以去看一下mysql字符串度设置为多长合适,提示: Mysql5 是个分界线.)

UTF-8是可变长编码,他将Unicode字符根据不同的数字代销分为1-6个字节,常用的英文字符为1个字节,汉字是三个字节,只有很偏僻的字符才是4-6个字节、 好的,这个时候就开始担心 如果这样操作的话会不会时间复杂度比较高? 这个我有想过,你们也可以去搜一下,这种疑问的习惯很不错,但是小心陷入局部技术陷阱

由上可得:大量只支持ASCII编码的历史遗留软件可以在UTF-8编码格式下正常解析。

在目前计算机内存当中,统一使用Unicode编码,当需要保存到硬盘或者需要传输的时候,就转换为UTF-8编码。

在用记事本进行编辑的时候,从文件中读取的UTF-8字符被转换为Unicode放到内存当中,编辑完毕之后,保存的时候再把Unicode转换为UTF-8进行保存。

1.4 闲扯

其实在工作当中一般情况下遇不到这种编码问题,只有在写爬虫的时候可能会遇到这种问题。

但是对于Python程序员来说特别是以前的2, 这就很难受了。

在最新的Python3中,字符串是以Unicode编码的,也就是说,Python的字符串支持多种语言,并且现在基本上也没那么多编码问题了。

对于单个字符的编码,Python提供了ord()函数来获取字符的整数表示,chr()函数把编码转换为对应的字符:

>>> ord(\'A\')
65
>>> ord(\'中\')
20013
>>> chr(66)
\'B\'
>>> chr(25991)
\'文\'

知道中文的整数编码,还可以用十六进制这样编写str:

>>> \'\\u4e2d\\u6587\'
\'中文\'

Python中字符串类型是str,在内存中用Unicode表示,一个字符对应若干个字节,如果要在网络上传输,或者保存到磁盘上就需要str变为字节为单位的bytes.

  • pythonbytes类型的数据用带\'b\'的前缀表示。
a = "asd"

a
Out[41]: \'asd\'

b = b"asd"

b
Out[43]: b\'asd\'

要注意的是两者虽然表示的内容一样,但是第二个每个字符只占用一个字节。
Unicode表示的str通过encode()方法可以编码为制定的bytes

>>> \'ABC\'.encode(\'ascii\')
b\'ABC\'
>>> \'中文\'.encode(\'utf-8\')
b\'\\xe4\\xb8\\xad\\xe6\\x96\\x87\'
>>> \'中文\'.encode(\'ascii\')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: \'ascii\' codec can\'t encode characters in position 0-1: ordinal not in range(128)

纯英文的str可以用ASCII编码为bytes,内容是一样的,因为英文字符ASCII也就只占一个字符,只有在被编码为Unicode的时候要占两个字节,前面需要补0。

含有中文的str可以用UTF-8编码会bytes。当然中文无法转ASCII

当然我们在磁盘或者网络中获取字节流之后,读取到的数据是bytes,要把bytes变为str,就要用decode()方法:

>>> b\'ABC\'.decode(\'ascii\')
\'ABC\'
>>> b\'\\xe4\\xb8\\xad\\xe6\\x96\\x87\'.decode(\'utf-8\')
\'中文\'

如果bytes中包含无法解码的字节,decode()方法会报错。

>>> b\'\\xe4\\xb8\\xad\\xff\'.decode(\'utf-8\')
Traceback (most recent call last):
  ...
UnicodeDecodeError: \'utf-8\' codec can\'t decode byte 0xff in position 3: invalid start byte

如果bytes中只有一部分无效的字节,可以传入errors=\'ignore\'忽略错误的字节

>>> b\'\\xe4\\xb8\\xad\\xff\'.decode(\'utf-8\', errors=\'ignore\')
\'中\'

len()方法用于计算str包含多少个字符

>>> len(\'ABC\')
3
>>> len(\'中文\')
2

如果将其转化为bytes的话,len()函数就计算字节数

>>> len(b\'ABC\')
3
>>> len(b\'\\xe4\\xb8\\xad\\xe6\\x96\\x87\')
6
>>> len(\'中文\'.encode(\'utf-8\'))
6

在操作字符串时,我们经常遇到strbytes的互相转换。为了避免乱码问题,应当始终坚持使用UTF-8编码对strbytes进行转换。

由于Python源代码也是一个文本文件,所以,当你的源代码中包含中文的时候,在保存源代码时,就需要务必指定保存为UTF-8编码。当Python解释器读取源代码时,为了让它按UTF-8编码读取,我们通常在文件开头写上这两行:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

第一行注释是为了告诉Linux/OS X系统,这是一个Python可执行程序,Windows系统会忽略这个注释;Windows是通过文件名后缀辨识文件类型的,例如exetxt。 但是基于Unix的系统是通过文件内容辨识文件类型的。所以需要加上第一行的代码。

第二行注释是为了告诉Python解释器,按照UTF-8编码读取源代码,否则,你在源代码中写的中文输出可能会有乱码。但是在编译器中也需要设置为UTF-8编码

申明了UTF-8编码并不意味着你的.py文件就是UTF-8编码的,必须并且要确保文本编辑器正在使用UTF-8 without BOM编码:

1.5

Java 解码


try {
    BufferedReader reader = new BufferedReader(new InputStreamReader(getMethod.getResponseBodyAsStream(), StandardCharsets.ISO_8859_1));

    String tmp = null;
    StringBuilder htmlRet = new StringBuilder();
    while ((tmp = reader.readLine()) != null) {
        htmlRet.append(tmp).append("\\r\\n");
    }
    System.out.println(new String(htmlRet.toString().getBytes(StandardCharsets.ISO_8859_1), "GB2312"));
} catch (IOException e) {
    e.printStackTrace();
} finally {
    getMethod.releaseConnection();
    System.out.println(getMethod.getResponseCharSet());
}

主要参考:

  • 文中可点击链接
  • 廖雪峰网站

以上是关于字符串和编码的主要内容,如果未能解决你的问题,请参考以下文章

从 XML 声明片段获取 XML 编码:部分内容解析不支持 XmlDeclaration

《安富莱嵌入式周报》第279期:强劲的代码片段搜索工具,卡内基梅隆大学安全可靠C编码标准,Nordic发布双频WiFi6 nRF7002芯片

Sublime Text自定制代码片段(Code Snippets)

使用非utf-8编码在Python中解析XML

InputStream的三个read的区别

以下代码片段 C++ 的说明