字符串相关函数
*capitalize 字符串首字母大写
*title 每个单词的首字母大写
*upper 将所有字母变成大写
*lower 将所有字母变成小写
*swapcase 大小写互换
*len 计算字符串的长度
*count 统计字符串中某个元素的数量
*find 查找某个字符串第一次出现的索引位置
*index 与 find 功能相同 find找不到返回-1,index找不到数据直接报错
*startswith 判断是否以某个字符或字符串为开头
*endswith 判断是否以某个字符或字符串结尾
*isupper 判断字符串是否都是大写字母
*islower 判断字符串是否都是小写字母
istitle 判断字符串是否每个单词都首字母大写
isalnum 判断字符串是否是由数字、字母、汉字组成
*isalpha 判断字符串是否由字母和文字组成
*isdigit 检测字符串数是数字组成 接受二进制字节流
*isdecimal 检测字符串是否以数字组成 必须是纯数字
isnumeric 检测字符串是否以数字组成 接受中文"四"
isspace 判断字符串是否由空白符组成
*split 按某字符将字符串分割成列表(默认字符是空格)
*join 按某字符将列表拼接成字符串(容器类型都可)
splitlines 按换行来进行切分(\n)
zfill 填充字符串(默认填充0,原字符串右对齐)
ljust 填充字符串,原字符居左 (默认填充空格)
rjust 填充字符串,原字符居右 (默认填充空格)
*center 填充字符串,原字符居中 (默认填充空格)
*strip 默认去掉首尾两边的空白符
rstrip 去掉右边某个字符
lstrip 去掉左边某个字符
创新互联公司专注于巴里坤哈萨克网站建设服务及定制,我们拥有丰富的企业做网站经验。 热诚为您提供巴里坤哈萨克营销型网站建设,巴里坤哈萨克网站制作、巴里坤哈萨克网页设计、巴里坤哈萨克网站官网定制、重庆小程序开发服务,打造巴里坤哈萨克网络公司原创品牌,更为您提供巴里坤哈萨克网站排名全网营销落地服务。
replace()
功能: 把字符串的旧字符换成新字符
格式: 字符串.replace('旧字符','新字符'[, 限制替换的次数])
返回值: 替换之后的字符串
maketrans translate 是一对
maketrans()
功能: 制作用于字符串替换的映射表
格式: 字符串.maketrans('查找字符','替换字符')两个字符必须长度相等
返回值: 字典
translate()
功能: 进行字符串替换操作
格式: 字符串.translate(maketrans返回的字典)
返回值: 替换之后的字符串
列表的相关函数
append()
功能:向列表的末尾添加新的元素
格式:列表.append(值)
返回值:None
注意:新添加的值在列表的末尾,该函数直接操作原有列表
insert()
功能:在指定索引之前插入元素
格式:列表.insert(索引,值)
返回值:None
注意:直接改变原有列表
extend()
功能:迭代追加所有元素
格式:列表.extend(可迭代性数据)
返回值:None
注意:直接改变原有列表
pop()
功能:通过指定索引删除元素,若没有索引移除最后那个
格式:列表.pop(索引)
返回值:删除的元素
(注意:没有指定索引,默认移除最后一个元素 )
remove()
功能:通过给予的值来删除,如果多个相同元素,默认删除第一个
格式:列表.remove(值)
返回值:无
(注意:如果有索引的情况推荐使用pop,效率高于remove)
clear()
功能:清空列表
格式:列表.clear()
返回值:空列表
index()
功能:获取某个值在列表中的索引
格式:列表.index(值[,start][,end]) # [] 表达参数可选项
返回值:找到返回索引 (找不到报错)
count()
功能:计算某个元素出现的次数
格式:列表.count(值)
返回值:次数
sort()
功能:列表排序(默认小到大排序)
格式:列表.sort(reverse=False)
返回值:None
注意:直接更改原列表
reverse()
功能:列表反转操作
格式:列表.reverse()
返回值:None
注意:直接更改原列表
深拷贝浅拷贝
copy模块中有 浅拷贝 和 深拷贝 两种方法
(1)浅拷贝: 浅拷贝只拷贝外层列表 内层列表跟随原列表进行改变
浅拷贝copy.copy(listvar) 或者 listvar.copy()
(2)深拷贝: 拷贝整个列表 内外列表都不跟随原列表进行改变
深拷贝copy.deepcopy(listvar)
注意:copy模块的copy方法 和 python内置的函数copy一样 都是浅拷贝
元组相关操作和方法
元组的相关操作除了不能修改和删除其中的元素之外 , 剩下操作都和列表相同.
元组里面能用的方法只有 index 和 count
字典的相关函数
fromkeys() 使用一组键和默认值创建字典
pop() 通过键去删除键值对 (若没有该键可设置默认值,预防报错)
popitem() 删除最后一个键值对
clear() 清空字典
update() 批量更新(有该键就更新,没该键就添加)
get() 通过键获取值(若没有该键可设置默认值,预防报错)
keys() 将字典的键组成新的可迭代对象
values() 将字典中的值组成新的可迭代对象
items() 将字典的键值对凑成一个个元组,组成新的可迭代对象
集合中的交差并补
intersection() 交集
difference() 差集
union() 并集
symmetric_difference() 对称差集 (补集情况涵盖在其中)
issubset() 判断是否是子集
issuperset() 判断是否是父集
isdisjoint() 检测两集合是否不相交 不相交 True 相交False
集合相关的函数
add() 向集合中添加数据
update() 迭代着增加
clear() 清空集合
pop() 随机删除集合中的一个数据
remove() 删除集合中指定的值(不存在则报错)
discard() 删除集合中指定的值(不存在的不删除 推荐使用)
冰冻集合
frozenset 可强转容器类型数据变为冰冻集合
冰冻集合一旦创建,不能在进行任何修改,只能做交叉并补操作
文件操作
打开模式
w write 写入模式
文件不存在则创建文件,存在的话则打开清空内容,并且将文件指针放在文件的开头
r read 读取模式
文件不存在则报错! 存在的话则打开文件,并且将文件指针放在文件的开头
a append 追加模式
文件不存在则创建文件,存在的话则打开文件,*并且将文件指针放在文件的末尾*
x xor 异或模式
文件已存在则报错! 不存在的话则创建文件,将文件指针放在文件的开头
扩展模式 (配合打开模式的辅助模式,自己单独不能使用)
+ plus 增强模式(可以让文件具有读写功能)
b bytes bytes模式(二进制字节流)
模式一共16种
w,w+,wb,wb+
r,r+,rb,rb+
a,a+,ab,ab+
x,x+,xb,xb+
将字符串和字节流(Bytes流)类型进行转换 (参数写成转化的字符编码格式)
encode() 编码 将字符串转化为字节流(Bytes流)
decode() 解码 将Bytes流转化为字符串
(utf-8编码格式下 默认一个中文三个字节 一个英文或符号 占用一个字节)
read() 功能: 读取字符的个数(里面的参数代表字符个数)
seek() 功能: 调整指针的位置(里面的参数代表字节个数)
tell() 功能: 当前光标左侧所有的字节数(返回字节数)
文件相关函数
readline() 功能: 读取一行文件内容
readlines() 功能:将文件中的内容按照换行读取到列表当中
writelines() 功能:将内容是字符串的可迭代性数据写入文件中 参数:内容为字符串类型的可迭代数据
truncate() 功能: 把要截取的字符串提取出来,然后清空内容将提取的字符串重新写入文件中 (字节)
readable() 功能: 判断文件对象是否可读
writable() 功能: 判断文件对象是否可写
函数
____doc____
__doc__或者help查看文档
return
return返回值
为这个函数返回一个结果 (return返回值可有可无 按照需求选择)
注意:执行return语句之后,函数执行结束
内置函数
abs 绝对值函数
round 四舍五入 (n.5 n为偶数则舍去 n.5 n为奇数,则进一!)
sum 计算一个序列得和
max 获取一个序列里边的最大值
min 获取一个序列里边的最小值
pow 计算某个数值的x次方
range 产生指定范围数据的可迭代对象
bin 将10进制数据转化为二进制
oct 将10进制数据转化为八进制
hex 将10进制数据转化为16进制
chr 将ASCII编码转换为字符
ord 将字符转换为ASCII编码
eval 将字符串当作python代码执行
eval 将字符串当作python代码执行(功能更强大)
repr 不转义字符输出字符串
input 接受输入字符串
hash 生成哈希值
全局变量 与 局部变量 及 其关键字的使用
globals() :返回字典,存放着全局作用域所有内容
locals() :返回字典,当前作用域所有内容(locals调用之前的变量)
global :关键字:声明全局变量获修改全局变量
nonlocal :关键字:修改局部变量(当前函数上一层的局部变量)
匿名函数
lambda 函数表达式: 只实现一些简单的函数功能,但是写法非常简便
高阶函数
高阶函数:能够把函数当成参数传递的就是高阶函数
map
map(func,iterable)
功能:
把iterable里面所有数据 一一的放进到func这个函数中进行操作 ,把结果扔进迭代器
参数:
func 内置或自定义函数
iterable 具有可迭代性的数据 ([迭代器],[容器类型的数据],[range对象])
返回值:
返回最后的迭代器
reduce
reduce(func,iterable)
功能:
先把iterable里面的前2个数据拿到func函数当中进行运算,得到结果,
在把计算的结果和iterable中的第三个数据拿到func里面进行运算,
依次类推 ,直到iterable里面的所有数据都拿完为止,程序结束
参数:
func 内置或自定义函数
iterable 具有可迭代性的数据 ([迭代器],[容器类型的数据],[range对象])
返回值:
计算的最后结果
sorted
sorted(iterable,reverse=False,key=函数)
功能:
对数据进行排序
参数:
iterable : 具有可迭代性的数据(迭代器,容器类型数据,可迭代对象)
reverse : 是否反转 默认为False 代表正序, 改成True 为倒序
key : 指定函数 内置或自定义函数
返回值:
返回排序后的数据
filter
filter(func,iterable)
功能:
用来过滤的,如果func函数中返回True , 会将这个值保留到迭代器中
如果func函数中返回False , 会将此值舍弃不保留
参数:
func : 自定义函数
iterable : 具有可迭代性的数据(迭代器,容器类型数据,可迭代对象)
返回值:
返回处理后的迭代器
列表推导式,集合推导式,字典推导式的相关写法
(1)enumerate
enumerate(iterable,[start=0])
功能:枚举 ; 将索引号和iterable中的值,一个一个拿出来配对组成元组,通过迭代器返回
参数:
iterable: 可迭代性数据 (常用:迭代器,容器类型数据,可迭代对象range)
start: 可以选择开始的索引号(默认从0开始索引)
返回值:迭代器
(2)zip
zip(iterable, ... ...)
功能: 将多个iterable中的值,一个一个拿出来配对组成元组,通过迭代器返回
iterable: 可迭代性数据 (常用:迭代器,容器类型数据,可迭代对象range)
返回: 迭代器
生成器send 与 yield from
send
next和send区别:
next 只能取值
send 不但能取值,还能发送值
send注意点:
第一个 send 不能给 yield 传值 默认只能写None
最后一个yield 接受不到send的发送值
yield from : 将一个可迭代对象变成一个迭代器返回
yield from : 将一个可迭代对象变成一个迭代器返回
序列化模块-pickle
dumps 把任意对象序列化成一个bytes
loads 把任意bytes反序列化成原来数据
dump 把对象序列化后写入到file-like Object(即文件对象)
load 把file-like Object(即文件对象)中的内容拿出来,反序列化成原来数据
数学模块-math
ceil() 向上取整操作 (对比内置round)
floor() 向下取整操作 (对比内置round)
pow() 计算一个数值的N次方(结果为浮点数) (对比内置pow)
sqrt() 开平方运算(结果浮点数)
fabs() 计算一个数值的绝对值 (结果浮点数) (对比内置abs)
modf() 将一个数值拆分为整数和小数两部分组成元组
copysign() 将参数第二个数值的正负号拷贝给第一个 (返回一个小数)
fsum() 将一个容器数据中的数据进行求和运算 (结果浮点数)(对比内置sum)
圆周率常数 pi
随机模块-random
random() 获取随机0-1之间的小数(左闭右开)
randrange() 随机获取指定范围内的整数(包含开始值,不包含结束值,间隔值)
randint() 随机产生指定范围内的随机整数
uniform() 获取指定范围内的随机小数(左闭右开)
choice() 随机获取序列中的值(多选一)
sample() 随机获取序列中的值(多选多) [返回列表]
shuffle() 随机打乱序列中的值(直接打乱原序列)
时间模块-time
time() 获取本地时间戳
ctime() 获取本地时间字符串(参数是时间戳,默认当前)
localtime() 获取本地时间元组 (参数是时间戳,默认当前)
mktime() 通过时间元组获取时间戳 (参数是时间元组)
asctime() 通过时间元组获取时间字符串(参数是时间元组)
sleep() 程序睡眠等待
strftime() 格式化时间字符串(格式化字符串,时间元祖)
strptime() 将时间字符串通过指定格式提取到时间元组中(时间字符串,格式化字符串)
perf_counter() 用于计算程序运行的时间
格式化时间字符串
格式 含义 %a 本地(locale)简化星期名称
%A 本地完整星期名称
%b 本地简化月份名称
%B 本地完整月份名称
%c 本地相应的日期和时间表示
%d 一个月中的第几天(01 - 31)
%H 一天中的第几个小时(24 小时制,00 - 23)
%I 一天中的第几个小时(12 小时制,01 - 12)
%j 一年中的第几天(001 - 366)
%m 月份(01 - 12) %M 分钟数(00 - 59)
%p 本地 am 或者 pm 的相应符
%S 秒(01 - 61)
%U 一年中的星期数(00 - 53 星期天是一个星期的开始)第一个星期天之前的所有天数都放在第 0 周
%w 一个星期中的第几天(0 - 6,0 是星期天) %W 和 %U 基本相同,不同的是 %W 以星期一为一个星期的开始
%X 本地相应时间
%y 去掉世纪的年份(00 - 99)
%Y 完整的年份
%z 用 +HHMM 或 -HHMM 表示距离格林威治的时区偏移(H 代表十进制的小时数,M 代表十进制的分钟数)
%% %号本身
不常用的属性函数(了解)
*gmtime() 获取UTC时间元祖(世界标准时间)
*time.timezone 获取当前时区(时区的时间差)
*time.altzone 获取当前时区(夏令时)
*time.daylight 获取夏令时状态
日历模块-calendar(了解内容)
calendar() 获取指定年份的日历字符串 (年份,w日期间的宽度,l日期间的高度,c月份间的间距,m一行显示几个月)
calendar.calendar(2018,w=2,l=2,c=20,m=1)
month() 获取指定年月的日历字符串 (年份,月份,w日期之间的宽度,l日期之间的高度)
calendar.month(2018,9,w = 2,l = 2)
monthcalendar() 获取指定年月的信息列表 (年份,月份) 0从周一开始排
calendar.monthcalendar(2018,9)
isleap() 检测是否是润年(能被4整除不能被100整除或能被400整除)
calendar.isleap(2004)
leapdays() 指定从某年到某年范围内的润年个数
calendar.leapdays(1970,2038)
monthrange() 获取某年某月的信息 周一是0
calendar.monthrange(2018,8)
weekday() 指定某年某月某日是星期几
calendar.weekday(2018,8,18)
timegm() 将时间元组转化为时间戳
ttp = (2018,10,1,13,23,34,0,0,0)
calendar.timegm(ttp)
os模块-对系统进行操作
system() 在python中执行系统命令
popen() 执行系统命令返回对象,通过read方法读出字符串
listdir() 获取指定文件夹中所有内容的名称列表
getcwd() 获取当前文件所在的默认路径
chdir() 修改当前文件工作的默认路径
environ 获取或修改环境变量
--os 模块属性
name 获取系统标识 linux,mac ->posix windows -> nt
sep 获取路径分割符号 linux,mac -> / window-> \
linesep 获取系统的换行符号 linux,mac -> \n window->\r\n 或 \n
os路径模块 -os.path
basename() 返回文件名部分
dirname() 返回路径部分
split() 将路径拆分成单独的文件部分和路径部分 组合成一个元组
join() 将多个路径和文件组成新的路径 可以自动通过不同的系统加不同的斜杠 linux / windows\
splitext() 将路径分割为后缀和其他部分
getsize() 获取文件的大小
isdir() 检测路径是否是一个文件夹
isfile() 检测路径是否是一个文件
islink() 检测路径数否是一个链接
getctime() [windows]文件的创建时间,[linux]权限的改动时间(返回时间戳)
getmtime() 获取文件最后一次修改时间(返回时间戳)
getatime() 获取文件最后一次访问时间(返回时间戳)
exists() 检测指定的路径是否存在
isabs() 检测一个路径是否是绝对路径
abspath() 将相对路径转化为绝对路径
os 与 shutil 模块 都具备对文件的操作
-- os模块具有 新建/删除/
os.mknod 创建文件
os.remove 删除文件
os.mkdir 创建目录(文件夹)
os.rmdir 删除目录(文件夹)
os.rename 对文件,目录重命名
os.makedirs 递归创建文件夹
os.removedirs 递归删除文件夹(空文件夹)
shutil模块
-- shutil模块 复制/移动/
copyfileobj(fsrc, fdst[, length=16*1024]) 复制文件 (length的单位是字符(表达一次读多少字符))
copyfile(src,dst) #单纯的仅复制文件内容 , 底层调用了 copyfileobj
copymode(src,dst) #单纯的仅复制文件权限 , 不包括内容 (虚拟机共享目录都是默认777)
copystat(src,dst) #复制所有状态信息,包括权限,组,用户,修改时间等,不包括内容
copy(src,dst) #复制文件权限和内容
copy2(src,dst) #复制文件权限和内容,还包括权限,组,用户,时间等
copytree(src,dst) #拷贝文件夹里所有内容(递归拷贝)
rmtree(path) #删除当前文件夹及其中所有内容(递归删除)
move(path1,paht2) #移动文件或者文件夹
json模块
所有编程语言都能够识别的数据格式叫做json,是字符串
dumps 把任意对象序列化成一个str
loads 把任意str反序列化成原来数据
dump 把对象序列化后写入到file-like Object(即文件对象)
load 把file-like Object(即文件对象)中的内容拿出来,反序列化成原来数据
json 和 pickle 两个模块的区别:
(1)json序列化之后的数据类型是str,所有编程语言都识别,
但是仅限于(int float bool)(str list tuple dict None)
json不能连续load,只能一次性拿出所有数据
(2)pickle序列化之后的数据类型是bytes,
所有数据类型都可转化,但仅限于python之间的存储传输.
pickle可以连续load,多套数据放到同一个文件中
压缩模块-zipfile (后缀为zip)
zipfile.ZipFile(file[, mode[, compression[, allowZip64]]])
ZipFile(路径包名,模式,压缩or打包,可选allowZip64)
功能:创建一个ZipFile对象,表示一个zip文件.
参数:
-参数file表示文件的路径或类文件对象(file-like object)
-参数mode指示打开zip文件的模式,默认值为r
r 表示读取已经存在的zip文件
w 表示新建一个zip文档或覆盖一个已经存在的zip文档
a 表示将数据追加到一个现存的zip文档中。
-参数compression表示在写zip文档时使用的压缩方法
zipfile.ZIP_STORED 只是存储模式,不会对文件进行压缩,这个是默认值
zipfile.ZIP_DEFLATED 对文件进行压缩
-如果要操作的zip文件大小超过2G,应该将allowZip64设置为True。
压缩文件
1.ZipFile() 写模式w打开或者新建压缩文件
2.write(路径,别名) 向压缩文件中添加文件内容
3.close() 关闭压缩文件
解压文件
1.ZipFile() 读模式r打开压缩文件
2.extractall(路径) 解压所有文件到某个路径下
extract(文件,路径) 解压指定的某个文件到某个路径下
3.close() 关闭压缩文件
追加文件(支持with写法)
ZipFile() 追加模式a打开压缩文件
查看压缩包中的内容namelist()
压缩模块-tarfile(后缀为.tar | .tar.gz | .tar.bz2)
bz2模式的压缩文件较小 根据电脑的不同会差生不同的结果 (理论上:bz2压缩之后更小,按实际情况为标准)
w 单纯的套一个后缀 打包
w:bz2 采用bz2算法 压缩
w:gz 采用gz算法 压缩
压缩文件
#1.open('路径包名','模式','字符编码') 创建或者打开文件
#2.add(路径文件,arcname="别名") 向压缩文件中添加文件
#3,close() 关闭文件
解压文件
1.open('路径包名','模式','字符编码') 读模式打开文件
2.extractall(路径) 解压所有文件到某个路径下
extract(文件,路径) 解压指定的某个文件到某个路径下
3.close() 关闭压缩文件
追加文件
open() 追加模式 a: 打开压缩文件 正常添加即可
查看压缩包中的内容getnames()
正则表达
匹配单个字符 => [元字符] 预定义字符集
预定义字符集 | 匹配内容 |
. |
匹配任意字符,除了换行符\n |
\d |
匹配数字 |
\D |
匹配非数字 |
\w |
匹配字母或数字或下划线 (正则函数中,支持中文的匹配) |
\W |
匹配非字母或数字或下划线 |
\s |
匹配任意的空白符 |
\S |
匹配任意非空白符 |
\n |
匹配一个换行符 |
\t |
匹配一个制表符 |
[] |
匹配中括号内列举的字符 |
字符组格式 | 说明 [默认必须从字符组中选一个] |
[...] |
匹配字符组中的字符 |
[^...] |
匹配除了字符组内所有内容,之外的所有字符 |
字符组内容 | 待匹配字符 | 匹配结果 | 说明 |
[0] |
8 |
True |
字符组里枚举的各种字符,必须满足一个,否则返回假,不匹配 |
[abcdefg] |
9 |
False |
由于字符组中没有"9"字符,所以不匹配 |
[0-9] |
7 |
True |
可用 - 表示范围,[0-9] 和 [0]是一个意思 |
[a-z] |
s |
True |
[a-z]匹配所有的小写字母 |
[A-Z] |
B |
True |
[A-Z]就表示所有的大写字母 |
[0-9a-fA-F] |
e |
True |
可以匹配数字,大小写形式的a-f. 该正则可验证十六进制 |
(二) 匹配多个字符 => [元字符] 量词符号
量词 |
用法说明 |
|
|
--- |
--- |
|
|
? |
重复0次或1次 |
|
|
+ |
重复1次或多次 (至少1次) |
|
|
* |
重复0次或多次 (任意次) |
|
|
{n} |
重复n次 |
|
|
{n,} |
重复n次或更多次 (至少n次) |
|
|
{n,m} |
重复n到m次 |
|
|
.* .+ |
贪婪模式匹配 |
|
|
.*? .+? |
非贪婪模式匹配 |
|
贪婪匹配: 默认向更多次数匹配 (底层用的是回溯算法)
非贪婪匹配: 默认向更少次数匹配 (量词的后面加?号)
(1)量词( * ? + {} )加上问号?表示非贪婪 惰性匹配
(2)例:.*?w 表示匹配任意长度任意字符遇到一个w就立即停止
匹配开头结尾 => [元字符] 边界符号
边界符 | 说明 |
\b |
匹配一个字符的边界 |
^ |
匹配字符串的开始 |
$ |
匹配字符串的结尾 |
#### (四) 匹配分组 => [元字符] 分组符号 |
|
分组 |
用法说明 |
--- |
--- |
a|b |
匹配字符a 或 字符b (如果两个当中有重合部分,把更长的那个放前面) |
(ab) |
匹配括号内的表达式 ,将()作为一个分组 |
\num |
引用分组num匹配到的字符串 |
(?P) |
给分组命名 |
(?P=name) |
引用别名: 把name分组所匹配到的内容引用到这里 |
分组
1.正常分组 ()
1) 正常情况下用()圆括号进行分组 可以用\1 反向引用第一个圆括号匹配的内容。
2) (?:正则表达式) 表示取消优先显示的功能
(正则表达式) 代表分组 findall 把所有分组的内容显示到列表里
(?:正则表达式) 代表分组 findall 把所有分组的内容不显示到列表里
2.命名分组
3) (?P<组名>正则表达式) 给这个组起一个名字
4) (?P=组名) 引用之前组的名字,把该组名匹配到的内容放到当前位置
正则表达式修饰符
常用修饰符 | 说明 |
re.I |
使匹配对大小写不敏感 |
re.M |
使每一行都能够单独匹配(多行匹配),影响 ^ 和 $ |
re.S |
使 . 匹配包括换行在内的所有字符 |
正则相关函数
findall 匹配字符串中相应内容,返回列表 [用法: findall("正则表达式","要匹配的字符串")]
search 通过正则匹配出第一个对象返回,通过group取出对象中的值
match 验证用户输入内容
split 切割
sub 替换
subn 替换
finditer 匹配字符串中相应内容,返回迭代器
compile 指定一个统一的匹配规则
当前名称:python函数快查快用
标题网址:
http://cdkjz.cn/article/dsojoce.html