字符串和编码
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了字符串和编码相关的知识,希望对你有一定的参考价值。
字符串和编码
标签(空格分隔): Python
1、历史
1.1 字符串
字符串:是一种数据类型,但是字符串比较特殊的还有一个就是编码问题。
1.2 bit和byte
bit
是比特,byte
是字节
因为计算机只能处理数字,要处理文本,就必须把文本装换成数字才能处理,最早的计算机载机设计时采用\\(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个字节)。现代操作系统和大多数编程语言都直接支持Unicode
。ASCII
用的是一个字节,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
.
python
对bytes
类型的数据用带\'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
在操作字符串时,我们经常遇到str
和bytes
的互相转换。为了避免乱码问题,应当始终坚持使用UTF-8
编码对str
和bytes
进行转换。
由于Python
源代码也是一个文本文件,所以,当你的源代码中包含中文的时候,在保存源代码时,就需要务必指定保存为UTF-8
编码。当Python
解释器读取源代码时,为了让它按UTF-8
编码读取,我们通常在文件开头写上这两行:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
第一行注释是为了告诉Linux/OS X
系统,这是一个Python
可执行程序,Windows
系统会忽略这个注释;Windows
是通过文件名后缀辨识文件类型的,例如exe
,txt
。 但是基于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芯片