格式化字符串f-string概览
f-string,亦称为格式化字符串常量(formatted string literals),是Python3.6新引入的一种字符串格式化方法,该方法源于PEP 498 – Literal String Interpolation,主要目的是使格式化字符串的操作更加简便。f-string在形式上是以 f 或 F 修饰符引领的字符串(f’xxx’ 或 F’xxx’),以大括号 {} 标明被替换的字段;f-string在本质上并不是字符串常量,而是一个在运行时运算求值的表达式:
简单使用
f-string用大括号 {} 表示被替换字段,其中直接填入替换内容:
1 | >>> name = 'Eric' |
表达式求值与函数调用
1 | >>> f'A total number of {24 * 8 + 4}' |
引号、大括号与反斜杠
1 | >>> f"He said {"I'm Eric"}" |
lambda表达式
1 | >>> f'result is {(lambda x: x ** 2 + 1) (2)}' |
正则表达式
re.match 函数
1 | re.match(pattern,string,flags=0) |
re.search 方法
1 | re.search(pattern,string,flags=0) |
re.match 与 re.search 的区别
re.match 只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回 None;而 re.search 匹配整个字符串,直到找到一个匹配
检索和替换
1 | re.sub(pattern,repl,string,count=0,flags=0) |
re.compile 函数
compile 函数用于编译正则表达式,生成一个正则表达(Pattern)对象,供 match() 和 search() 这两个函数使用。
1 | re.compile(pattern[,flags]) |
findall
1 | findall(string[,pos[,endpos]]) |
re.split
1 | re.split(pattern, string[, maxsplit=0, flags=0]) |
KMP算法
字符串匹配是极为常见的一种模式匹配。简单地说,就是判断主串 T 中是否出现模式串 P,即 P 为 T 的子串。特别地,定义主串 T[0…n-1],模式串为 P [0…p-1],则主串与模式串的长度各为 n 与 p
暴力匹配
暴力匹配方法的思想非常朴素:
- 依次从主串的首字符开始,与模式串逐一进行匹配
- 遇到失配时,则移到主串的第二个字符,将其与模式串首字符比较,逐一进行匹配
- 重复上述步骤,直至能匹配上,或剩下主串的长度不足以进行匹配
1 | s = "asdadadsfasdfasdfasdtest" |
算法复杂度分析:i 在主串上移动 (n-p)次,匹配失败时,j 移动次数最多有 p-1 次。因此复杂度为 O(n*p)
对于暴力匹配而言,就存在重复匹配的现象。比如,第一次匹配失败时,主串,模式串失败匹配的位置的字符分别为 a 与 c ,下一次匹配时主串,模式串的起始位置分别为 T1 与 P[0];而在模式串中 c 之前是 ab ,未有重复结构,因此 T1与 P[0]肯定不能匹配上,这样造成了重复匹配。直观上,下一次匹配应从 T2 与 P[0] 开始。
KMP 算法原理
KMP 算法思想归纳如下:将主串 T 的第一个字符与模式串 P 的第一个字符进行匹配。如果相等,则依次比较 T 和 P 的下一个字符。如果不相等,则 主串 T 移动(已匹配字符数-对应的部分匹配值)位,继续匹配。
关于移动位数的解释:已匹配字符数,即当前已完成匹配的字符数量。部分匹配值就是前缀和后缀的最长的共有元素的长度。
前缀指除了最后一个字符以外,一个字符串的全部头部组合
后缀指除了第一个字符以外,一个字符串的全部尾部组合
举个例子:以”ABCDABD”为例1
2
3
4
5
6
7
8
9
10
11
12"A"的前缀和后缀都为空集,共有元素的长度为 0;
"AB"的前缀为[A],后缀为[B],共有元素的长度为 0;
"ABC"的前缀为[A, AB],后缀为[BC, C],共有元素的长度 0;
"ABCD"的前缀为[A, AB, ABC],后缀为[BCD, CD, D],共有元素的长度为 0;
“ABCDA"的前缀为[A, AB, ABC, ABCD],后缀为[BCDA, CDA, DA, A],共有元素为"A”,长度为 1;
“ABCDAB"的前缀为[A, AB, ABC, ABCD, ABCDA],后缀为[BCDAB, CDAB, DAB, AB, B],共有元素为"AB”,长度为 2;
"ABCDABD"的前缀为[A, AB, ABC, ABCD, ABCDA, ABCDAB],后缀为[BCDABD, CDABD, DABD, ABD, BD, D],共有元素的长度为 0。
部分匹配表如下:
搜索值 A B C D A B D
部分匹配值 0 0 0 0 1 2 0
算法实现1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39def same_start_end(s):
"""最长前后缀相同的字符位数"""
n = len(s) # 整个字符串长度
j = 0 # 前缀匹配指向
i = 1 # 后缀匹配指向
result_list = [0] * n
while i < n:
if j == 0 and s[j] != s[i]: # 比较不相等并且此时比较的已经是第一个字符了
result_list[i] = 0 # 值为0
i += 1 # 向后移动
elif s[j] != s[i] and j != 0: # 比较不相等,将j值设置为j前一位的result_list中的值,为了在之前匹配到的子串中找到最长相同前后缀
j = result_list[j - 1]
elif s[j] == s[i]: # 相等则继续比较
result_list[i] = j + 1
j = j + 1
i = i + 1
return result_list
def kmp(s, p):
"""kmp算法,s是字符串,p是模式字符串,返回值为匹配到的第一个字符串的第一个字符的索引,没匹配到返回-1"""
s_length = len(s)
p_length = len(p)
i = 0 # 指向s
j = 0 # 指向p
next = same_start_end(p)
while i < s_length:
if s[i] == p[j]: # 对应字符相同
i += 1
j += 1
if j >= p_length: # 完全匹配
return i - p_length
elif s[i] != p[j]: # 不相同
if j == 0: # 与模式比较的是模式的第一个字符
i += 1
else: # 取模式当前字符之前最长相同前后缀的前缀的后一个字符继续比较
j = next[j]
if i == s_length: # 没有找到完全匹配的子串
return -1