python2字符串编码方式_一、基础部分-2.字符串编码

一、字符编码历史

1. ASCII

美国人搞了个ASCII码表,把123abcABC%$#(数字、字母、特殊符号) ,全部用10进制的数字表示。例如数字65,代表着“A” ,ASCII码表一共255个数字,基本代表米国常用英文和符号(其实127以后都不是太常用的了)

2. GB2312-->GBK-->GB18030

中国汉字那么多,255个数字显然不够表示。所以中国人发明了GB2312(6千个常用简体汉字),后来又搞了GBK(2万多汉字,并且包含中日韩中的汉字),再后来又搞了一个GB18030(2.7万汉字,包含中国的少数民族语言)

3. Unicode

每个国家不同语言,都需要有自己的编码表,很麻烦。

而且如果日本的软件出口到中国,中国电脑一打开就会乱码(因为没装日本的编码表,软件内文字会乱码)。

再或者,如果一个文件中包含日语、中文、英文,那打开后就乱码了。于是,Unicode国际统一码(2-4个字节)诞生了。 至少用16个2进制表示:11111111 11111111 (2个bytes)

Unicode其实是一张很大的对应关系表,对应着1个字符,在unicode的位置,以及这个字符在ascii码中的位置。

所以,无论你使用何种编码,都能转换成unicode码,而unicode码又能转换成任何其他编码(可以理解unicode左手牵着你编码的字符,右手牵着其他国家的各种编码,额unicode是千手观音,有很多手)。

这样的话,无论你使用GBK、ASCII、或者其他国家对字符进行编码,都能通过这张大表,找到对应其他编码的位置。

4. UTF-8

使用unicode全球人民都很高兴,终于不再出现乱码了,但是美国、英国人不高兴了。

因为以前他们都使用ASCII码,存一个电影1个GB,现在用Unicode变成了2个GB了(因为ASCII码一共255个数字就可以表示美国人使用的常用字符,255转换成二进制:1111 1111(十进制转二进制),是1个bytes。而Unicode至少2个bytes,所有使用unicode编码的文件,就会比ascii码多一倍大小)

于是乎,为了优化unicode,节省字节。又搞出了UTF-8(英文继续用1个字节,欧洲用2个字节,东南亚用3个字节),注意:使用unicode的时候中文是2个字节,现在使用UTF8变成了3个字节表示了,这占空间啊,很蛋疼,但没办法。

5. 其他知识:

数据文件存到硬盘上是2进制的,像这样: 01010100100101001(尽然没逗号,那计算机怎么断句呢?其实计算机会一次性读取8位2进制,不足8位的补0)

你使用ascii码对你的文件编码,并保存到硬盘。当你打开的时候(就是读到内存的时候),就必须也要指定使用ascii码打开。如果你错误的使用GBK打开,那肯定乱码了。总的来说,什么方式存进去的,什么方式读出来。

windows系统默认使用GBK编码,也就是说,当你存一个文件到磁盘的时候,如果你不指定使用什么编码,默认使用GBK给你编码(Mac、 Linux系统默认UTF8编码)

二、Python2与Python3编码不同

Python3 读取文件的流程:

Python3解析器,按照文件头定义的编码进行解析。(如果你在文件头,不指定编码方式。python3默认使用UTF-8去读取)

Python3自动把你的编码格式,转换成Unicode到内存中。

按照代码内容语义分析,去解析执行。

所有的变量、字符都是以Unicode编码去声明

总结:在Python3中,无论读取中文、英文或其他国家语言编码的文件,在打印的时候都不会乱码,因为都进行了自动转换,变成了Unicode。(现在的所有操作系统,都支持Unicode编码)

Python2 读取文件的流程:

Python2默认使用ASCII编码,去尝试读取文件。

Python2把ASCII编码加载到内存中(注意:不会像Python3一样,帮你自动转换成Unicode到内存哦)

如果你文件中包含中文,直接就乱码了,因为ASCII表中没有中文啊。

别急,通常在编写Python2文件时候,都在文件头加:#coding: utf-8,目的是想告诉Python2解释器,在读取文件时,别在使用默认的ASCII了,要使用UTF-8编码去读取。

这下,终于把代码以UTF-8读取到内存了。

还没完,如果你使用Windows电脑,Windows默认打印终端使用GBK编码,在终端打印的时候,你发现依然还是乱码了(崩溃了~)。

Windows是支持Unicode或GBK打印的,所以,还需要你把内存中的UTF-8手动转换成Unicode或者GBK,才能正常打印。

如何手动转换呢:

UTF8 ---> Unicode 把UTF8转换成Unicode的过程,称为:解码(decode)

Unicode ---> UTF8/GBK 把unicode编码转换成UTF8或者GBK的过程,称为:编码(encode)

总结一下:

Python3文件默认编码UTF-8(默认用utf-8读到内存),在内存中,python3的字符串编码是unicode(Python3自动帮你把utf-8转成了unicode到内存中了)

Python2文件默认编码ASCII码(默认用ASCII码读到内存),在内存中,python2字符串默认你按照什么编码读出来的,在内存就是什么编码(如果你声明了文件头,就按照头声明来编码读到内存中)。

Python2中,Unicode是个单独的数据类型。

三、深入Python2字符编码

1. 问题出现了

想判断数据类型,使用type()函数。python2中unicode是一种单独的数据类型,而GBK和UTF-8使用type()函数判断类型时,都返回str类型。这样的话,我怎么知道,到底是GBK还是UTF8呢?有人说可以使用len()函数去判断,因为GBK是使用2个字符代表一个中文字,而UTF8使用3个字符代表一个中文字。如下:

#!/usr/bin/env python2.7

#encoding:utf-8

s = "中"

#unicode

s2 = s.decode("utf-8")

print "我运行在python2中,我声明了文件头是UTF8。虽然python2不会自动把我转换成unicode,但我可以自己使用decode函数手工转换,你看,我现在就变成了unicode编码了,我在python2中表现的数据类型是:%s " %type(s2)

#GBK

s3 = s2.encode("gbk") #注意:s2经过上一步的转换,已经变成了unicode编码了。s3现在相当于,在用encode函数把unicode编码成了GBK。

print "我是gbk编码的,我在python2中的数据类型是:%s, 我的长度是:%s" % (type(s3),len(s3))

#UTF8

s4 = s2.encode("utf-8")

print "我是utf-8编码的,我在python2中的数据类型是:%s , 我的长度是:%s " %(type(s4),len(s4))

#运行结果:

我运行在python2中,我声明了文件头是UTF8。虽然python2不会自动把我转换成unicode,但我可以自己使用decode函数手工转换,你看,我现在就变成了unicode编码了,我在python2中表现的数据类型是:

我是gbk编码的,我在python2中的数据类型是:, 我的长度是:2

我是utf-8编码的,我在python2中的数据类型是: , 我的长度是:3

问题确实存在,gbk编码、utf-8编码,在python2中的数据类型都是str。

我如何知道一个字符串到底是gbk编码的还是utf8编码的呢?

虽然可以看长度,gbk用2个字节,代表1个中文,utf-8用3个字节,代表1个中文汉字。这没错,那是因为举得例子简单,如果无数个字节,比如这样:'\xd6\xd0...bulabulabula一大堆',让你判断,这些字节的编码是什么?那怎么办呢?

2. 难道是巧合?

1. 突然想起来,有那个Unicode对应关系表啊..(http://www.unicode.org/charts/ 下载:CJK Unified Ideographs (Han) )

>>> s = "中"

>>> s_unicode = s.decode("utf-8")

>>> s_unicode

u'\u4e2d'

>>>

>>> s_gbk = s_unicode.encode("gbk")

>>> s_gbk

'\xd6\xd0'

>>>

>>> s_utf8 = s_unicode.encode("utf-8")

>>> s_utf8

'\xe4\xb8\xad'

总结下,这个"中"字:

unicode编码是长这样: u'\u4e2d'

gbk编码是长这样的: '\xd6\xd0'

UTF8编码是长这样的: '\xe4\xb8\xad'

2. 赶紧下载,并打开Unicode对应表:

搜索"中"字,恩,"中"字旁边的Unicode确实写着:4E2D。

但我们关心的是GBK啊,GBK上写着: G0-5650(16进制)。

这5650 和 我们上面打印的'\xd6\xd0'也不完全对啊,但是貌似对了2位。6和0对了,5没对。

3. gbk编码打印是这样的:'\xd6\xd0',这是16进制,换成2进制试试看。

d6(16进制)--->11010110(2进制) PS: 4位2进制,代表1个16进制,所以 1101 代表d(13) 0110代表6

d0(16进制)--->11010000(2进制)

4. 即便把16进制换成2进制,感觉也和G0-5650没啥关系啊,这样,把上面的2进制的第一位,去掉不算****,试试看:

\xd6\xd0 中的d6,11010110(2进制)--->1101 0110--->去掉每组第1位不算--->0101 0110--->转成16进制--->56

\xd6\xd0 中的d0, 11010000(2进制)--->1101 0000--->去掉每组第1位不算--->0101 0000)--->转成16进制--->50

5. 我擦嘞~,当去掉1位后,就正好是5650。和Unicode表上的GBK编码对应上了...为什么要去掉1位呢?

3. 原来是这样

GBK是兼容ASCII码的,如何实现的?

首先:GBK是每2个字节代表1个中文,ASCII码是1个字节代表1个英文字母的。

如果给你一个2个2进制(2个字节)11010110 11010000,你怎知道是代表1个中文,还是2个ASCII码的英文字符呢?

正好,ASCII码常用的就127个,7位2进制最大就是127,就可以表示了,还剩下1位。

中国人设计GBK的时候,考虑到想兼容ASCII码。想到,既然ASCII码的127往后至255都不常用。那我们利用剩下的这1位做文章。

[x] 如果,2个2进制(2个字节),每个2进制的第1位,都被设置成了1,它就是中文。

[x] 如果,1个2进制(1个字节),第一位是1,那就是按照ASCII编码,是英文。

举例:11010110 11010000 这2个二进制,第1位都被都设置了1,这是个中文。

总结:

GBK编码中,为了兼容ASCII码,1个2进制的字节,第一位,如果设置成1,叫高字节。如果设置成0,代表低字节。2个连续的高字节,就是中文。**

Unicode表中,"中"字符--> 本来应该用d6d0表示,但是它忽略了高字节--->所以变成了这样 G0-5650

其实,UTF-8 也是利用了高字节,来区分ASCII编码的。不然一堆连续的2进制,怎么判断啊?

四、Python str和bytes类型

1. python2中的str和bytes没啥区别

python2

>>> s = "中"

>>> print s

中 #称之为字符串 (其实是字形)

>>> s

'\xe4\xb8\xad' #字符串"中"字,在编码表里的位置。 是二进制数据串(只不过16进制表现形式)

其实按理说,print 应该打印 '\xe4\xb8\xad' 这个位置,但是print帮你打印了这个位置对应的"中"字 (其实这个"中"字就是一个图片字形)

总结:

根据2进制的数据串,在编码表中找到对应的关系,然后在找到的那个字形,就是字符串。

一堆二进制数据串儿,python称他为bytes(注意有 s结尾,复数)。

概念上"中"字符串(字形)和 '\xe4\xb8\xad'二进制串儿bytes 不是一种东西,但是本质上,却都指向了相同的一个东西。

所以,python2中,直接把字符串"str" 类型等于了 bytes类型。

实例:

#python2里,把bytes类型和字符串类型,都称为字符串"str",不区分,如下:。

>>> s_str = "中"

>>> print type(s_str)

#字符串就是str类型

>>>

>>> s_bytes = b"中" #b"字符串" -->定义一个bytes类型

>>> print type(s_bytes)

#bytes类型 也是 str类型

>>>

2. 既然python2的bytes类型和字符串str是一会儿事儿,为什么还要搞一个bytes类型呢( b"字符串" ) ?

因为之所以能显示中文字形,是因为二进制串儿bytes,在Unicode编码表中找到了对应的图形,然后给展示出来。

但图片、视频读到内存中,图片没编码(没unicode这种东西),那怎么办呢?实际上,图片是一堆2进制流,对应成了屏幕像素快颜色,最终展示出来的。

既然图片是一堆二进制流,那么这一堆数据流,怎么表示他们呢?就只能用bytes类型表示。

print图片会乱码,因为图片又不是文字,如果你非要print图片,那print就会尝试把图片里的二进制流到unicod编码表中找对应关系,但最终肯定会乱码的。

也就是说,字符、图片、视频等,都是bytes类型。但字符因为有Unicode那张表存在,可以找到对应关系。

所以字符中的bytes,可以转成字符串str(字形),而字符串"str",也肯定能转换成bytes。

但图片、音频中的bytes,则不能转换成字符串str(因为他们本来也不是字,是图啊..)

3. Python3 数据保存和传输

Python3的字符串类型是str,在内存中以Unicode表示,一个字符对应若干个字节。如果要在网络上传输,或者保存到磁盘上,就需要把str变为以字节为单位的bytes,像这样:x = b'ABC'

以Unicode表示的str通过encode()方法可以编码为指定的bytes,例如:

#Python3

>>> type("ABC")

>>> 'ABC'.encode('ascii') #把英文的str变成了bytes

b'ABC'

>>> '中文'.encode('utf-8') #把中文的str变成了bytes

b'\xe4\xb8\xad\xe6\x96\x87'

反过来,如果我们从网络或磁盘上读取了字节流,那么读到的数据就是bytes。要把bytes变为str,就需要用decode()方法:

>>> b'ABC'.decode('ascii') #把英文bytes转换成了str

u'ABC'

>>> type(b'ABC'.decode('ascii')) #通过type()函数查看,python3中str就是unicode类型。

>>> b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8') #把中文的bytes转成str

u'\u4e2d\u6587'

>>> print(b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8')) #打印时,就可以显示字形了。

中文

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

len()函数计算的是str的字符数,如果换成bytes,len()函数就计算字节数:

>>> len('ABC')

3

>>> len('中文')

2

>>>

>>> len(b'ABC')

3

>>> len(b'\xe4\xb8\xad\xe6\x96\x87')

6

4. 总结

Python2

str = bytes

为什么要有bytes类型?因为要表示图片和音频等,二进制格式的数据。

python2,即便以utf-8编码的字符串,在windows上仍然不能显示(windows默认是GBK)。

怎样才能正常显示?手动转unicode编码decode("utf8")。

还有一个办法,在pythno2中,定义一个字符串时,在前面加个u,例如:u"中",这时候打印类型print type,结果:

python2 中,unicode类型可以表示字符串,还可以使用str表示字符串。

有点儿乱,但是unicode是为了显示全球文字,而设计的类型。如果只有英文字符,str类型就够了。

以utf-8、gbk等编码的文件,加载到内存时,还依然是 utf-8、gbk (不帮你转换unicode,读到什么,就是什么)

所以说,python2中,如果以gbk格式编码的文件,加载到内存还是gbk,在print打印时,就是gbk格式的bytes。

Python3

以utf-8 gbk等编码的文件,加载到内存时,自动帮你转换成unicode。所以,在python3中看到的str字符串,都是unicode格式编码的bytes。

也就是说python3,默认支持了全球化语言(因为str都是unicode编码的),

python3中已经没有了单独的unicode类型了,因为str就是Unicode,既str = unicode。

在python2中,str = bytes,之所以多个bytes类型是为了表示图片等。而python3 str是str (str = unicode), bytes就是bytes,没关系。

注意,在内存中可以是unicode展示,这没问题。但当你存储到硬盘、网络传输,当然不能用unicode存(unicode只是张对照表),需要unicode转换成gbk或utf-8编码格式的,然后换成bytes去存储或传输。

也就是说,python3中 str(unicode编码)就仅仅是打印使用的,真正字符串传输、或者存盘,都会转换成bytes。

那为啥Python2有 str、Unicode,而Python3就只有str类型了(python3中str就是Unicode)?

因为在python2初期开发的时候,就没考虑到全球化问题,默认用的ASCII码。后来python普及后,各国开发者呼吁支持全球化语言,所以python2没办法,单独又造了一个Unicode类型。

#python2实例

>>> s = "str"

>>> s_unicode = s.decode("utf-8") #python2中,unicode类型是单独的。

>>> s_gbk = s_unicode.encode("gbk") #把unicode编码成gbk

>>> type(s_gbk)

#打印时发现,gbk编码的类型显示为str。

#python3实例

>>> s = "str" #python3 字符串str都是unicode

>>> s_gbk = s.encode("gbk") #把unicode编码成gbk

>>> type(s_gbk)

#打印时发现, gbk编码的类型是 bytes。(不再和python2一样是str类型了)

结论:

1. 在python2中,str = bytes,之所以多个bytes类型是为了表示图片等二进制流。

2. 在python3中,字符串str就是str字形 (str都是由unicode编码), bytes就是bytes,明确告诉你,你想看字符串str的字形,必须的是unicode编码。而图片二进制流,没办法编码和解码,传输时一律使用bytes类型。

参考链接:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/311338.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python基本语法复习——嗯...貌似很久没写过博客了

文章目录引入包math库random库string列表元组装包、拆包字典类与继承json异常处理引入包 import random import math import jsonmath库 print(math.ceil(4.1)) print(math.floor(4.9)) print(math.fabs(-10)) print(math.sqrt(9)) print(math.exp(1))分别是:向上…

Istio 1.5 发布——拥抱变化,爱上单体

北京时间 2020 年 3 月 6 日凌晨,我们期待已久的 Istio 1.5 发布了,发布公告见 https://istio.io/news/releases/1.5.x/announcing-1.5/。由 ServiceMesher 社区组织翻译的 Istio 官方文档同时发布,见 https://istio.io/zh。Istio 1.5 是一个…

[蓝桥杯][历届试题]连号区间数

题目描述 小明这些天一直在思考这样一个奇怪而有趣的问题: 在1~N的某个全排列中有多少个连号区间呢?这里所说的连号区间的定义是: 如果区间[L, R] 里的所有元素(即此排列的第L个到第R个元素)递增排序后能得到一个长度为…

hbuilderx怎么添加断点_【高考语文题库】高考一直提分提不上去该怎么办?同一卷高考押题语文答案,助你再提30分...

大树从来不是在温室里长成的,而是在风霜雪雨的洗礼中参天的……古语云:“工欲善其事,必先利其器。”俗话说:“磨刀不误砍材工。”用到学习上就是学习必须讲究学习方法,有了适合自己的有效学习方法必定会事半功倍。一个…

业务模块化打造单体和分布式部署同步支持方案

我在2019年中国.NET开发者峰会上为大家分享了我们的微服务电商安全工程实践,那次会议分享的高清录播已经上传到我的腾讯课堂,大家可以通过底部的小程序打开直接观看(复习)。在大会上跟大家提到,我们当时只有4个人的创业…

[蓝桥杯][基础练习VIP]FJ的字符串-递归

题目描述 FJ在沙盘上写了这样一些字符串: A1 “A” A2 “ABA” A3 “ABACABA” A4 “ABACABADABACABA” … … 你能找出其中的规律并写所有的数列AN吗? 输入 仅有一个数:N ≤ 26。 输出 请输出相应的字符串AN,以一个换行…

python编程加油_编程学习资料,中途加油站,c++/java/python/小程序/人工智能......等等等等...

资料仅供学习分享用,废话不多说,解压密码为:1024文件是切割压缩的,多个part的压缩包,大家需要先下载到本地在解压,直接百度云解压会提示压缩包损坏。------------------------------学习资料java&#xff1…

[蓝桥杯][算法提高VIP]开灯游戏-dfs

题目描述 有9盏灯与9个开关,编号都是1~9。 每个开关能控制若干盏灯,按下一次会改变其控制的灯的状态(亮的变成不亮,不亮变成亮的)。 具体如下: 第一个开关控制第二,第四盏灯; 第二个开关控制第一&#…

python爬虫百度贴吧代码大全_零基础写python爬虫之抓取百度贴吧代码分享

这里就不给大家废话了,直接上代码,代码的解释都在注释里面,看不懂的也别来问我,好好学学基础知识去!# -*- coding: utf-8 -*-#---------------------------------------# 程序:百度贴吧爬虫# 版本&…

Asp.Net Core EndPoint 终结点路由工作原理解读

Asp.Net Core EndPoint 终点路由工作原理解读一、背景在本打算写一篇关于Identityserver4 的文章时候,却发现自己对EndPoint -终结点路由还不是很了解,故暂时先放弃了IdentityServer4 的研究和编写;所以才产生了今天这篇关于EndPoint (终结点…

[蓝桥杯][算法提高VIP]夺宝奇兵-dp

题目描述 在一座山上,有很多很多珠宝,它们散落在山底通往山顶的每条道路上,不同道路上的珠宝的数目也各不相同.下图为一张藏宝地图: 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 ”夺宝奇兵”从山下出发,到达山顶,如何选路才能得到最多的珠宝呢?在上图所示例子中,按照5-> 7-> 8-&g…

迁移到其他机器_有赞大数据离线集群迁移实战

‍‍点击关注“有赞coder”获取更多技术干货哦~作者:郭理想 & 任海潮部门:数据中台一、背景有赞是一家商家服务公司,向商家提供强大的基于社交网络的,全渠道经营的 SaaS 系统和一体化新零售解决方案。随着近年来社…

C# 客户端内存优化分析

背景概述C# 开发客户端系统的时候,.net 框架本身就比较消耗内存资源,特别是xp 这种老爷机内存配置不是很高的电脑上运行,所以就需要进行内存上的优化,才能流畅的在哪些低端电脑上运行. 想要对C# 开发的客户端内存优化需要了解以下几个概念。虚拟内存这里…

xshell1分钟就会自动断_手术室自动门不能正常控制开关门维修案例

手术室自动门维修案例遵义市第五人民医院手术室的手术门。用户反映:不能正常控制开关门。一、原因分析:1.红外线安全传感器故障2.控制器故障3.直流电机故障4. 红外感应开关故障5.红外感应探头故障6.电源故障图1图2图3图4图5图6二、维修过程:1…

[蓝桥杯][基础练习VIP]芯片测试-思维

题目描述 有n块芯片,有好有坏,已知好芯片比坏芯片多。 每个芯片都能用来测试其他芯片。用好芯片测试其他芯片时,能正确给出被测试芯片是好还是坏。而用坏芯片测试其他芯片时,会随机给出好或是坏的测试结果(即此结果与…

.NET Core开发实战(第18课:日志框架:聊聊记日志的最佳姿势)--学习笔记(下)...

18 | 日志框架&#xff1a;聊聊记日志的最佳姿势除了使用 CreateLogger 指定 logger 的名称&#xff0c;实际上还可以借助容器来构造 logger&#xff0c;通常情况下我们会定义自己的类namespace LoggingSimpleDemo {public class OrderService{ILogger<OrderService> _lo…

[蓝桥杯][基础练习VIP]完美的代价-贪心

题目描述 回文串&#xff0c;是一种特殊的字符串&#xff0c;它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串&#xff0c;它不一定是回文的&#xff0c;请你计算最少的交换次数使得该串变成一个完美的回文串。 交换的定义是&#xff1a;交换两…

安卓手机 python控制_PyAndroidControl:使用python脚本控制你的安卓设备

有的时候玩游戏或者干什么想写写安卓的脚本&#xff0c;不过用 java 或者 kotlin 写图像处理什么的太麻烦了&#xff0c;按键精灵的脚本我也懒得学。adb 倒是可以&#xff0c;但是很多时候要用电脑&#xff0c;又有些不太方便。感觉现在云手机比较方便吧&#xff0c;比如说&…

《ASP.NET Core 微服务实战》送书结果公告

如何构建基于.NET Core和云环境下的微服务技术体系&#xff1f;的送书抽奖结果已经出来了&#xff1a;当前只有一位同学填写了地址。其他几位同学抓紧填写&#xff0c;3/9 日还没有完成填写将作废&#xff0c;奖品可是热门的《ASP.NET Core 微服务实战》。另外我公司商城上上线…

MarkDown的介绍

文章目录markdown是什么优点缺点代码高亮markdown是什么 markdown是一种标记语言&#xff0c;常用文字排版 优点 易读&#xff08;看起来很舒服&#xff09;&#xff0c;易写&#xff08;语法简单&#xff09;跨平台使用&#xff08;mac/win/linux等&#xff09;其他网站和软件…