6.1 字符串编码格式简介
- ASCII、GB2312、UTF-8不同编码格式之间相差很大,采用不同的编码格式意味着不同的表示和存储形式,把同一字符存入文件时,写入的内容可能会不同,在试图理解其内容时必须了解编码规则并进行正确的解码。
- 如果解码方法不正确就无法还原信息,从这个角度来讲,字符串编码也具有加密的效果。
- Python 3.X完全支持中文字符,默认使用UTF-8编码格式,无论是一个数字、英文字母,还是一个汉字,在统计字符串长度时都按一个字符对待和处理。
>>> s='中国山东烟台'
>>> len(s) #字符串长度,或者包含的字符个数
6
>>> s='中国山东烟台ABCDE' #中文与英文字符同样对待,都算一个字符
>>> len(s)
11
6.2 字符串
- 在Python中,字符串也属于序列类型,除了支持序列通用方法(包括切片操作)以外,还支持特有的字符串操作方法。
- 字符串属于不可变序列。
>>> testString='good'
>>> testString[0]='b'
Traceback (most recent call last):
File "<pyshell#5>", line 1, in <module>
testString[0]='b'
TypeError: 'str' object does not support item assignment
- Python字符串驻留机制:对于短字符串,将其赋值给多个不同的对象时,内存中只有一个副本,多个对象共享给该副本。长字符串不遵守驻留机制。
- 判断一个变量s是否为字符串,应使用isinstance()或type()。
6.2.1 字符串格式化
>>> x=1235
>>> so="%o"%x
>>> print(so)
2323
>>> sh="%x"%x
>>> print(sh)
4d3
>>> "%s"%65
'65'
>>> "%s"%65333
'65333'
>>> "%d"%"555"
Traceback (most recent call last):
File "<pyshell#13>", line 1, in <module>
"%d"%"555"
TypeError: %d format: a number is required, not str
- 使用format方法进行格式化
>>> print('{0:.3f},{1:.6f}'.format(1/3,2/3))
0.333,0.666667
>>> print('my name is {name},my age is{age},and my QQ is {qq}'.format(name='Dong Fuguo',age=37,qq="306467355"))
my name is Dong Fuguo,my age is37,and my QQ is 306467355
- 格式化的字符串常量
- Python 3.6.x开始支持新的字符串格式化方式,官方称为Formatted String Literals.
>>> width=10
>>> precision=4
>>> value=11/3
>>> f'result:{value:{width}.{precision}}'
'result: 3.667'
- 使用Tempplate模板进行格式化
Template()里面把字符串中某个值用设置变量${key}的方式先写好,然后在substitute()的方式把变量用其他值代替,就完成了字符串的替换。
>>> t=Template('My name is ${name},and is ${age} years old.')
>>> d={'name';'Dong','age':39}
SyntaxError: invalid syntax
>>> d={'name':'Dong','age':39}
>>> t.substitute(d)
'My name is Dong,and is 39 years old.'
6.3 字符串常用操作
- Python字符串对象提供了大量方法用于字符串的切分、连接、替换和排版等操作,另外还有大量内置函数和运算符也支持对字符串的操作。
- 字符串对象是不可变的,所以字符串对象提供的涉及到字符串"修改"的方法都是返回修改后的新字符串,并不对原始字符串做任何修改,无一例外。
6.3.1 字符串搜索
- find()、rfind()、index()、rindex()、count()
√ find()和rfind()方法分别从左(右)查找一个字符串在另一个字符串指定范围
(默认是整个字符串)中首次出现的位置,如果不存在则返回-1;
√ index()和rindex()方法用来返回一个字符串在另一个字符串指定范围中首次出现的位置,如果不存在则抛出异常;
√ count()方法用来返回一个字符串在当前字符串中出现的次数。
>>> s="apple,peach,banana,peach,pear"
>>> s.find("peach")
6
>>> s.find("peach",7)
19
>>> s.find("peach",7,20)
-1
>>> s.rfind("p")
25
>>> s.index("p")
1
>>> s.index("pe")
6
>>> s.index("pear")
25
>>> s.index("ppp")
Traceback (most recent call last):
File "<pyshell#137>", line 1, in <module>
s.index("ppp")
ValueError: substring not found
>>> s.count("p")
5
>>> s.count("pp")
1
>>> s.count("ppp")
0
- s.startswith(t)、s.endswith(t)
- 判断字符串是否以指定字符串开始或结束
>>> s='Beautiful is better than ugly.'
>>> s.startswith('Be') #检测整个字符串
True
>>> s.startswith('Be',5) #指定检测范围起始位置
False
>>> s.startswith('Be',0,5) #指定检测范围起始和结束位置
SyntaxError: invalid character in identifier
>>> s.startswith('Be',0,5) #指定检测范围起始和结束位置
SyntaxError: invalid character in identifier
>>> s.startswith('Be',0,5) #指定检测范围起始和结束位置
True
>>> import os
>>> [filename for filename in os.listdir('c:\\')if filename.endswith(('.bmp','.jpg','gif'))]
[]
6.3.2 字符串拆分
- split()、rsplit()、partition()、rpartition()
√ split()和rspilt()方法分别用来以指定字符为分隔符,把当前字符串从左往右或从右往左分隔成多个字符串,并返回包含分隔结果的列表;
√ paratition()和rpartition()用来以指定字符串为分隔符将原字符串分隔为3部分,即分隔符前的字符串、分隔符字符串、分隔符后的字符串,如果指定的分隔符不在原字符串中,则返回原字符串和两个空字符串。 - 对于split()和rsplit()方法,如果不指定分隔符,则字符串中任何空白符号(空格、换行符、制表符等)都将被认为是分隔符,把连续多个空白字符看作一个分隔符。
>>> s='hello world \n\n My name is Dong '
>>> s.split()
['hello', 'world', 'My', 'name', 'is', 'Dong']
>>> s='\n\nhello\t\t world \n\n\n My name\t is Dong '
>>> s.split()
['hello', 'world', 'My', 'name', 'is', 'Dong']
>>> s="apple,peach,banana,pear"
>>> s.split(",") #','是分隔符
['apple', 'peach', 'banana', 'pear']
>>> s.partition(',')
('apple', ',', 'peach,banana,pear')
>>> s.rpartition(',')
('apple,peach,banana', ',', 'pear')
>>> s="2017-10-31"
>>> t=s.split("-")
>>> print(t)
['2017', '10', '31']
>>> print(list(map(int,t)))
[2017, 10, 31]
- split()方法和rsplit()方法还允许指定最大分割次数。
>>> s='\n\nhello\t\t world \n\n\n My name\t is Dong '
>>> s.rsplit(None,2)
['\n\nhello\t\t world \n\n\n My name', 'is', 'Dong']
>>> s.split(maxsplit=6)
['hello', 'world', 'My', 'name', 'is', 'Dong']
>>> s.split(maxsplit=100) #最大分割次数大于可分割次数时无效
['hello', 'world', 'My', 'name', 'is', 'Dong']
- 然而,明确传递参数指定split()使用的分隔符时,情况是不一样的。
>>> 'a,,,bb,,ccc'.split(',') #每个逗号都被作为独立的分隔符
['a', '', '', 'bb', '', 'ccc']
>>> 'a\t\t\tbb\t\tccc'.split() #连续多个制表符被作为一个分隔符
['a', 'bb', 'ccc']
6.3.3 字符串组合
- 字符串连接 join()
>>> li=["apple","peach","banana","pear"]
>>> ','.join(li) # ','为连接符
'apple,peach,banana,pear'
>>> '::'.join(li)
'apple::peach::banana::pear'
6.3.4 字母大小写转换
- lower()、upper()、capitalize()、title()、swapcase()
>>> s="What is Your Name?"
>>> s.lower() #返回小写字符串
'what is your name?'
>>> s.upper() #返回大写字符串
'WHAT IS YOUR NAME?'
>>> s.capitalize() #字符串首字符大写
'What is your name?'
>>> s.title() #每个单词的首字母大写
'What Is Your Name?'
>>> s.swapcase() #大小写互换
'wHAT IS yOUR nAME?'
6.3.5 字符串替换
- 查找替换 replace()
>>> print("abcdabc".replace("abc","ABC"))
ABCdABC
- 问题解决:测试用户输入中是否有敏感词,如果有的话就把敏感词替换为3个星号***。
>>> words=('测试','非法','暴力','话')
>>> text='这句话里含有非法内容'
>>> for word in words:
if word in text:
text=text.replace(word,'***')
>>> text
'这句***里含有***内容'
- 字符串对象的marktrans()方法用来生成字符映射表,而translate()方法用来根据映射表中定义的对应关系转换字符串并替换其中的字符,使用这两个方法的组合可以同时处理多个字符。
>>> #创建映射表,将字符"abcdef123"--对应地转换为"uvwxyz@#$",这两个参数不是作为整体进行处理的。
>>> table=''.maketrans('abcdef123','uvwxyz@#$')
>>> s="Python is a grest programming language.Ilike it!"
>>> #按映射表进行替换
>>> s.translate(table)
'Python is u gryst progrumming lunguugy.Iliky it!'
- strip()、rstrip()、lstrip() 这三个函数的参数指定的字符串并不作为一个整体对待,而是在原字符串的两侧、右侧、左侧删除参数字符串中包含的所有字符,一层一层地从外往里扒。
>>> s=" abc "
>>> s.strip() #删除两端空白字符
'abc'
>>> "aaaassddf".strip("a") #删除指定字符
'ssddf'
>>> "aaaassddfaaa".rstrip("a") #删除字符串右端指定字符
'aaaassddf'
>>> "aaaassddfaaa".lstrip("a") #删除字符串左端指定字符
'ssddfaaa'
>>> 'aabbccddeeeffg'.strip('af') #字母f不在字符串两侧,所以不删除
'bbccddeeeffg'
>>> 'aabbccddeeeffg'.strip('gaf')
'bbccddeee'
>>> 'aabbccddeeeffg'.strip('gbaef')
'ccdd'
>>> 'aabbccddeeeffg'.strip('gbaefcd')
''
6.3.7 字符串类型测试
- isalnum()、isalpha()、isdigit()、isspace()、isupper()、islower()、istitle()等用来测试字符串是否为数字或字母、是否为字母、是否为数字字符、是否为空白字符、是否为大写字母、是否为小写字母及是否为首字母大写。
>>> '1234abcd'.isalnum()
True
>>> '1234abcd'.isalpha() #全部为数字时返回True
False
>>> '1234abcd'.isdigit() #全部为数字时返回True
False
>>> 'abcd'.isalpha()
True
>>> '1234.0'.isdigit()
False
>>>
6.3.8 字符串对齐处理
- center()、ljust()、rjust(),返回指定宽度的新字符串,原字符串居中、左对齐或右对齐出现在新字符串中,如果指定宽度大于字符串长度,则使用指定的字符(默认为空格)进行填充。zfill()返回指定宽度的字符串,在左侧以字符0进行填充。
>>> 'Hello world!'.center(20) #居中对齐,以空格进行填充
' Hello world! '
>>> 'Hello world!'.center(20,'=') #居中对齐,以字符=进行填充
'====Hello world!===='
>>> 'Hello world!'.ljust(20,'=') #左对齐
'Hello world!========'
>>> 'Hello world!'.rjust(20,'=') #右对齐
'========Hello world!'
>>> 'uio'.zfill(20)
'00000000000000000uio'
- 字符串内置函数:Len(),max(),min(),eval(),input().
- 字符串切片操作:切片也适用于字符串,但仅限于读取其中的元素,不支持字符串的修改。
6.4 正则表达式
- 正则表达式是字符串处理的有力工具和技术。
- 正则表达式使用某种预定义的模式去匹配一个一类具有共同特征的字符串,主要用于处理字符串,可以快速、准确地完成复杂的查找、替换等处理要求。
- Python中,re模块提供了正则表达式操作所需要的功能。
- 正则表达式在文本编辑与处理、网页爬虫之类的场合中有重要应用。
6.4.1 正则表达式元字符
- 最简单的正则表达式是普通字符串,可以匹配自身
- '[pjc]ython' 可以匹配'python'、'jython'、'cython'。
- '[a-zA-Z0-9]'可以匹配一个任意大小写字母或数字''
- '[^abc]'可以一个匹配任意除'a'、'b'、'c'之外的字符。
- 'python|perl'或'p(ython|erl)'都可以匹配'python'或'perl'
- 子模式后面加上问号表示可选。r'(http://)?(www.)?python.org'只能匹配'http://www.python.org'、'http://python.org'、'www.python.org'和'python.org'
- ‘^http’只能匹配所有以'http'开头的字符串
- (pattern)*:允许模式重复0次或多次
- (pattern)+:允许模式重复1次或多次
- (pattern){m,n}:允许模式重复m~n次
6.4.2 直接使用re模块方法
re模块主要方法:
- compile(pattern[,flags]):创建模式对象
- search(pattern,string[,flags]):在字符串中寻找模式
- match(pattern,string[,flags]):从字符串的开始匹配模式
- findall(pattern,string[,flags]):列出字符串中模式的所有匹配项
- split(pattern,string[,maxsplit=0]):根据模式匹配项分割字符串
- sub(pat,repl,string[,count=0]):将字符串中所有pat的匹配项用repl替换
- escape(string):将字符串中所有特殊正则表达式字符转义
其中,flag是匹配模式,其值可以是re.I(忽略大小写)、re.L、re.M(多行匹配模式)、re.S(使元字符‘.’匹配任意字符,包括换行符)、re.U(匹配Unicode字符)、re.X(忽略模式中的空格)并可以使用#注释的不同组合。
>>> import re
>>> text='alpha.beta...gamma delta'
>>> re.split('[\.]+',text)
['alpha', 'beta', 'gamma delta']
>>> re.split('[\.]+',text,maxsplit=2) #分割2次
['alpha', 'beta', 'gamma delta']
>>> pat='[a-zA-Z]+'
>>> re.findall(pat,text) #查找所有单词
['alpha', 'beta', 'gamma', 'delta']
>>> pat='{name}'
>>> text='Dear {name}...'
>>> re.sub(pat,'Mr.Dong',text) #字符串替换
'Dear Mr.Dong...'
>>> print(re.match('done|quit','done')) #匹配成功
<re.Match object; span=(0, 4), match='done'>
>>> re.escape('http://www.python.org') #字符串转义
'http://www\\.python\\.org'
6.4.3 使用正则表达式对象
>>> import re
>>> example='ShanDong Institute of Business and Technology'
>>> pattern=re.compile(r'\bB\w+\b') #以B开头的单词
>>> pattern.findall(example)
['Business']
>>> pattern=re.compile(r'\b[a-zA-Z]{3}\b') #查找3个字母长的单词
>>> pattern.findall(example)
['and']