python3 の 正则:
针对python的string类型不方便修改的问题, 还是得用正则对字符串进行变更:
正则还是一如既往的好用🤣
参考资料:
https://www.runoob.com/python3/python3-reg-expressions.html
正则包为re
, import re 即可
re.match
re.match(pattern, string, flags=0)
与C++不同, 这玩意尝试从第一个字符开始匹配串, 但不要求整个串匹配, 只要是从头开始的都可以
参数 | 描述 |
---|---|
pattern | 匹配的正则表达式 |
string | 要匹配的字符串 |
flags | 标志位, 用于控制正则表达式的匹配方式, 如:是否区分大小写, 多行匹配等等参见:正则表达式修饰符 - 可选标志 |
返回值:
匹配成功re.match方法返回一个匹配的对象, 否则返回None
print(re.match(r"WDNMD", "WDNMD"))
print(re.match(r"WDNMD", "WDNMD?"))
print(re.match(r"WDNMD", "?WDNMD?"))
print(re.match(r"WDNMD", "???"))
<re.Match object; span=(0, 5), match=‘WDNMD’>
<re.Match object; span=(0, 5), match=‘WDNMD’>
None
None
其返回值比较特殊, 可以用于其他操作:
-
使用span()获取匹配的位置:
上述例子中可以看到, 有个span标签, 可以单独获取这个tuple:
line = "Cats are smarter are than are dogs" ans = re.search(r"are", line) print(ans) print(type(ans.span()))
<re.Match object; span=(5, 8), match=‘are’>
<class ‘tuple’> -
在正则中, 可以用括号分组, match之后便可以使用
group
获得这些组:line = "Cats are smarter than dogs" matchObj = re.match(r'(.*) are (.*?) .*', line) print("group(): ", matchObj.group()) print("group(1): ", matchObj.group(1)) print("group(2): ", matchObj.group(2))
group(): Cats are smarter than dogs
group(1): Cats
group(2): smarter
re.search()
re.search(pattern, string, flags=0)
这个函数与C++相同, 返回第一个适合的匹配, 返回的类型基本与match相似
函数参数说明:
参数 | 描述 |
---|---|
pattern | 匹配的正则表达式 |
string | 要匹配的字符串 |
flags | 标志位, 用于控制正则表达式的匹配方式, 如:是否区分大小写, 多行匹配等等参见:正则表达式修饰符 - 可选标志 |
这玩意与match的区别就是是否强制从第一个字符开始匹配
re.sub()
这个相当于C++中的 replace()
re.sub(pattern, repl, string, count=0, flags=0)
参数:
- pattern : 正则中的模式字符串
- repl : 替换的字符串, 也可为一个函数
- string : 要被查找替换的原始字符串
- count : 模式匹配后替换的最大次数, 默认 0 表示替换所有的匹配
- flags : 编译时用的匹配模式, 数字形式。
返回值:
函数返回替换完的字符串
参数中repl可以为函数, 所以可见python中的正则一定程度上是比C++支持的更好更强大的
基础修改替换功能就不看了, 基本与C++一样, 直接来看函数的使用
def fff(matched):
print(matched)
return "替换"
if __name__ == '__main__':
line = "Cats are smarter are than are dogs"
ans=re.sub("are", fff, line)
print("ans= ", ans)
<re.Match object; span=(5, 8), match=‘are’>
<re.Match object; span=(17, 20), match=‘are’>
<re.Match object; span=(26, 29), match=‘are’>
ans= Cats 替换 smarter 替换 than 替换 dogs
-
每匹配成功一次, 就会调用一次函数
-
获取到的结果与match的返回值类型相同, 可以使用分组命名的方法获取到匹配的值
-
sub会将匹配到的串替换为函数的返回值
python正则の高级用法:
捕获 & 分组:
在标准正则中, 捕获 & 分组的语法:
python中的实现稍有区别
需要加个P
def double(matched):
print(matched)
print(matched.group("value"))
value = int(matched.group('value'))
return str(value * 2)
if __name__ == '__main__':
s = 'A23G4HFD567'
print(re.sub('(?P<value>\d+)', double, s))
<re.Match object; span=(1, 3), match=‘23’>
23
<re.Match object; span=(4, 5), match=‘4’>
4
<re.Match object; span=(8, 11), match=‘567’>
567
A46G8HFD1134
零宽断言:
这个倒是可以按照正常语法使用:
def fff(matched):
print(matched)
return "替换"
if __name__ == '__main__':
s = 'ABCDEFGHIJKLM 2233N OPQRSTUVWXYZ'
print(re.sub(r'(?<=2233).?', fff, s))
print(re.sub(r"(?=N)", fff, s))
<re.Match object; span=(18, 19), match=‘N’>
ABCDEFGHIJKLM 2233替换 OPQRSTUVWXYZ
<re.Match object; span=(18, 18), match=’’>
ABCDEFGHIJKLM 2233替换N OPQRSTUVWXYZ
负向零宽断言:
这个也能按照常规语法使用:
def fff(matched):
print(matched)
return "替换"
if __name__ == '__main__':
s1 = "front Benqer after"
s2 = "front Benq after"
print(re.sub(r"\b\w*q[^u]\w*\b", fff, s1)) #本意是匹配单独的q后头没有u的单词
print(re.sub(r"\b\w*q[^u]\w*\b", fff, s2)) #但是如果遇到q结尾的单词就会出错
print(re.sub(r"\b\w*q(?!u)\w*\b", fff, s2)) #需要使用负向零宽断言解决
<re.Match object; span=(6, 12), match=‘Benqer’>
front 替换 after
<re.Match object; span=(6, 16), match=‘Benq after’>
front 替换
<re.Match object; span=(6, 10), match=‘Benq’>
front 替换 after
懒惰匹配:
其实就是尽可能少量的匹配:
def fff(matched):
print(matched)
return "替换"
if __name__ == '__main__':
s1 = "aabab"
print(re.sub(r"a.*b", fff, s1)) #贪婪匹配, 匹配尽可能长的串
print(re.sub(r"a.*?b", fff, s1)) #懒惰匹配, 匹配尽可能少的串
<re.Match object; span=(0, 5), match=‘aabab’>
替换
<re.Match object; span=(0, 3), match=‘aab’>
<re.Match object; span=(3, 5), match=‘ab’>
替换替换
特殊模式:
之前的几个方法中有个flag变量, 用来指定特殊的匹配模式:
在python中, 用如下形式指定:
平衡组:
这玩意用来匹配具有嵌套格式的玩意
有点复杂, 先放着