字符串与正则表达式

Python强大的一点就在于其文字处理。对于字符串,首先要知道的是字符串的编码,以及处理编码的一些函数;然后要知道字符串可以进行的操作与方法;对于正则表达式,首先要知道PCRE流派正则表达式的规则,然后是Python中使用正则表达式的方法。

字符串

第一篇中讲到字符串是Python中的一种基本类型,是一个字符序列,包括行内字符串和行间字符串。Python 3.x中字符串默认的编码方式是UTF-8编码。

字符编码

Unicode

Unicode是一种字符集。它于1994年正式公布,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,所以又称为统一码/万国码/单一码。不论什么字符,它都使用4字节来表达每个符号。

Python提供了ordchr两个内置函数,用于Unicode字符与机器内部Unicode编码值之间的转换。

  • 说明
    1. Unicode字符:我们在界面上看到的一个实际的字符。
    2. Unicode编码值:Unicode字符集将一个字符与一个唯一的编码相对应,这个编码就是对应Unicode字符的编码值。
  1. ord函数将一个字符转化为相应的Unicode编码值
  2. chr函数将一个整数转化为相应的Unicode字符

Untitled

UTF-8编码

UTF是Unicode Transformation Format,即Unicode传送格式的缩写。它是将Unicode文件转化为字节传送流在计算机中进行存储和传输的方式,相当于Unicode的一种再编码。

Unicode字符集采用四个字节为每个字符设定了一个唯一的编码,UTF-32编码就规定在计算机中使用4字节来存储每个字符。实际上,对于前面的字符,没必要采用4字节来存储。总结一下就是UTF-32的编码方式简单直接,但是浪费了很多空间

UTF-8编码改进了UTF-32编码,采用变长编码的方式:ASCII字符只需要一个字节来编码,而一些复杂的字符则需要占用2、3、4个字节。

面试官:请讲一下 Unicode 和 UTF-8 的区别?

由于Python默认采用UTF-8编码,所以我们甚至可以把中文作为标识符:

Untitled

其他编码

我们常用的编码还有GBK编码(GB2312→GBK→GB18030),它是针对中文的一种编码方式,且向下兼容ASCII码。由于它针对中文,所以使用GBK编码存储的中文字符的大小比UTF-8编码小,所以Windows时区设为中国时系统采用GBK编码也是有道理的。

  • 编码格式是GBK时,一个中文字符占2个字符。
  • 编码格式是UTF-8时,一个中文字符占3个字符。

Python提供了encode和decode两个方法来实现编码与解码:

  1. encode:将Unicode字符转化为指定的编码方式的编码值。函数内的参数是要采用的编码。
  2. decode:将指定编码方式的编码值解码为Unicode字符。

    Untitled

    可以到C语言中去进一步验证。gbk编码中一个汉字确实占两个字符:

    Untitled

字节类型

上面的b'\xd6\xd0\xb9\xfa'就是一个字节类型(bytes)的常量。在''前面加b表示这是一个字节类型,''里面的每一个字符是\x00-\xff之间的一个十六进制数或一个ASCII字符。

Untitled

它的操作和字符串很相似,了解即可。

索引与分片

索引

索引包括正索引与负索引。正索引的编号范围是0 ~ len(str)-1,负索引的编号范围是-len(str) ~ -1。所以可以很方便地访问到字符串后面的字符。

Untitled

分片

字符串的分片操作可以从给定的字符串中分离出部分字符。它的格式为str[start: end: step]

  1. 区间的范围为左闭右开,即不包括end对应的字符。
  2. step缺省默认为1。str[start:]表示从下标为start的位置一直到字符串末尾;str[:end]表示从字符串开始一直到end-1的位置。
  3. startend可以是正索引,也可以是负索引,还可以混用。但要求start经一个或多个step能得到end,否则分片返回的字符串为空。
  4. 如果要实现逆序输出到字符串开头,使用正索引是无法实现的,需要使用负索引:str[start:-(len(str)+1):-1]。而使用正索引无法切到第一个字符。(实际上要使用正索引可以缺省结束的位置,如str[start::-1]就可以从start逆序输出到字符串开头)

    Untitled

  5. 提供的start和end可以超过字符串的范围,超过了就认为一直切到底。

字符串的操作

使用运算符可以对字符串进行操作,从C++的角度可以认为对这些运算符进行了重载。

算数运算符

需要注意这些运算都不会改变字符串本身,而是返回一个新的字符串。

  1. 使用+连接字符串: 'abc'+'def'='abcdef'
  2. 使用*重复字符串: 'abc'*2='abcabc'

关系运算符

  1. 使用=判断两个字符串是否是相同
  2. 使用>、<、>=、<=来比较两个字符串的大小。

    字符的大小比的是字符编码值的大小,如英文字母比的是ASCII码的大小。字符串比大小就是从左到右比较个字符的大小,直到比较出结果。需要记住常用字符的ASCII码:0-9: 48-57;A-Z: 65-90;a-z: 97-122

  3. 使用in或not in判断前者是否是后者的字串(区别子串与子序列)。

字符串的常用方法

  • 函数与方法的区别

    称类/对象的成员函数为方法。具体来说,len(str)这种形式的称为函数;str.upper()这种形式的称为方法。

  1. 大小写转换
    • str.upper(): 全部字母转换为大写。
    • str.lower(): 全部字母转化为小写。
    • str.swapcase(): 大小写互换。
    • str.title(): 每个单词的首字母大写。
    • str.capitalize(): 字符串的首字母大写。
  2. 字符串对齐
    • str.ljust(width,fillchar):输出width个字符,原来的字符串左对齐,右边用fillchar填充。
    • str.rjust(width,fillchar):输出width个字符,原来的字符串右对齐,左边用fillchar填充。
    • str.center(width,fillchar):输出width个字符,原来的字符串在新串的中间,两边用fillchar填充。
  3. 字符串搜索
    • str.find(substr): 返回str从左到右第一个出现substr的首字符的位置;没有则返回-1。
    • str.rfind(substr): 返回str从右到左第一个出现substr的首字符的位置;没有则返回-1。
    • str.count(substr): 计算substrstr中出现的次数。
  4. 字符串替换

    • str.replace(oldstr,newstr,max): 将oldstr替换为newstrmax表示最多替换的次数,可省略。
  5. 字符串的拆分与组合

    • str.split(seq,max): 以seq作为分隔符,将str从左到右拆分为一个序列,max表示最多拆分的次数,可省略。
    • str.rsplit(seq,max): 从右到左拆分str为一个序列。

      如果seq不是str的子串,那么序列中的元素就是这个字符串本身。seq缺省表示以空格作为分隔。

    • str.join(seq): 以str作为序列seq中元素的分隔,将序列合并成一个字符串。

      Untitled

正则表达式

正则表达式Regular Expression是一种文本模式,它是一些元字符和普通字符的组合,用于实现对字符串的过滤逻辑,常常用来检索或替换符合某种模式的文本

元字符

元字符meta character是具有特定含义的字符,它使得正则表达式具有匹配能力。

  1. 首先需要区别括号的含义:()将内部的字符串作为一个整体;{}表示匹配次数;[]表示匹配其中的一个字符,可以用-表示一个范围。
  2. 然后要知道贪婪匹配与懒惰匹配。贪婪匹配会尽可能多地匹配字符,而懒惰匹配则是尽可能少地匹配。

Python使用正则表达式

Python中使用正则表达式有两种方式:使用正则表达式对象和使用正则表达式字符串。两种方式的区别是使用正则表达式对象调用的是它的方法,而使用字符串调用的是函数。使用正则表达式的基本步骤如下:

  1. 引入re模块
  2. 编辑正则表达式字符串,注意正则表达式必须是正确的写法,不然后面会报错。
  3. 如果要使用正则表达式对象,使用re.compile()正则表达式字符串编译为正则表达式对象。使用正则表达式对象可以加快处理速度。
  4. 正则字符串调用函数或正则对象调用方法。

需要掌握可以调用的函数或方法。

match

match的作用是从字符串的最左边开始匹配,不能从中间开始匹配,相当于自带了$。

1
2
3
4
5
6
7
8
import re
text='one1 two2 three3 four4'
pattern='.*?\d+'
# 使用正则字符串匹配到one1
print(re.match(pattern,text).group())
# 使用正则对象匹配到one1
regObj=re.compile(pattern)
print(regObj.match(text).group())

search的作用是扫描整个字符串,返回从左到右第一个匹配的结果。它可以从中间开始匹配

1
2
3
4
5
6
7
8
import re
text='one1 two2 three3 four4'
pattern="\s(\w)*"
# 使用正则字符串匹配到 two2
print(re.search(pattern,text).group())
# 使用正则对象匹配到 two2
regObj=re.compile(pattern)
print(regObj.search(text).group())

findall

findall的作用是扫描整个字符串,以列表的形式返回全部能匹配的结果。

1
2
3
4
5
6
7
8
import re
text='one1 two2 three3 four4'
pattern="\d"
# 使用正则字符串匹配到数字,返回列表
print(re.findall(pattern,text))
# 使用正则对象匹配到数字,返回列表
regObj=re.compile(pattern)
print(regObj.findall(text))

finditer

finditerfindall类似,区别是将结果组成一个迭代器返回。但是从迭代器取到的是一个match对象,所以还需要调用group()方法

1
2
3
4
5
6
7
8
9
10
11
import re
text='one1 two2 three3 four4'
pattern="\d"
# 使用正则字符串匹配到数字,返回列表
results=re.finditer(pattern,text)
for result in results:print(result.group())

# 使用正则对象匹配到数字,返回列表
regObj=re.compile(pattern)
results=regObj.finditer(text)
for result in results:print(result.group())

正则表达式深入研究是很高深的,什么有限自动机听着就很高深——本篇这点仅做入门用。re模块的常量还没有仔细看,之后可以再看看下面这篇文章。

Python正则表达式,这一篇就够了!