正则表达式是一种文本模式描述的工具,比如在word文档以及ppt中的文字查找,使用的都是正则表达式。它可以用来检索、替换那些符合某个模式(规则)的文本,在leetcode查找符合要求字符串中十分好用。
基本匹配
re.match(pattern, string)
: 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match() 就返回 None。re.search(attern, string)
: 扫描整个字符串并返回第一个成功的匹配。re.match()
和re.search()
都返回一个匹配对象(Match object),如果没有找到匹配则返回None
。re.compile(regex, flags=0),regex是正则表达式字符串,flags是可选的标志,用于修改正则表达式的行为
match_obj = re.match(r'\\d+', '123abc456')
if match_obj:
print(match_obj.group()) # 输出: '123'
高级匹配
re.findall(pattern, string)
: 在字符串中找到正则表达式所匹配的所有子串,并返回一个列表。re.finditer(pattern, string)
: 扫描整个字符串,找到正则表达式所匹配的所有子串,并返回一个迭代器,该迭代器产生 Match 对象。
print(re.findall(r'\\d+', '123abc456')) # 输出: ['123', '456']
替换文本
re.sub()
: 替换字符串中的一些匹配项。
re.sub(替换的对象,将替换成的内容,文本)
print(re.sub(r'\\d+', 'NUM', '123abc456')) # 输出: 'NUMabcNUM'
特殊序列
限定符
- a* a出现0次或多次
- a+ a出现1次或多次
- a? a出现0次或1次
- a{6} a出现6次
- a{2,6} a出现2-6次
- a{2,} a出现两次以上
或运算符
- (a|b) 匹配a或者b
- (ab)|(cd) 匹配ab或者cd
字符类
- [abc] 匹配a或者b或者c
- [a-c] 同上
- [a-fA-F0-9] 匹配小写+大写英文字符以及数字
- [^0-9] 匹配非数字字符
元字符
- \d 匹配数字字符
- \D 匹配非数字字符
- \w 匹配单词字符(英文、数字、下划线)
- \W 匹配非单词字符
- \s 匹配空白符(包含换行符、Tab)
- \S 匹配非空自字符
- . 匹配任意字符(换行符除外)
- \bword\b \b标注字符的边界(全字匹配)
- ^ 匹配行首
- $ 匹配行尾
贪婪/懒惰匹配
<.+> 默认贪婪匹配“任意字符”
<.+?> 懒惰匹配“任意字符”
上示例
说一句,刷题的目标也为了锻炼锻炼思维,直接用正则表达式有点违背这一初衷hhh,但能保证提交结果正确,这里说几个例子,以便各位熟练运用
注:有的题目是需要设计正则表达式,我们再用正则表达式来做这种题显然不合适。
请你来实现一个 myAtoi(string s)
函数,使其能将字符串转换成一个 32 位有符号整数。
函数 myAtoi(string s)
的算法如下:
- 空格:读入字符串并丢弃无用的前导空格(
" "
) - 符号:检查下一个字符(假设还未到字符末尾)为
'-'
还是'+'
。如果两者都不存在,则假定结果为正。 - 转换:通过跳过前置零来读取该整数,直到遇到非数字字符或到达字符串的结尾。如果没有读取数字,则结果为0。
- 舍入:如果整数数超过 32 位有符号整数范围
[−231, 231 − 1]
,需要截断这个整数,使其保持在这个范围内。具体来说,小于−231
的整数应该被舍入为−231
,大于231 − 1
的整数应该被舍入为231 − 1
。
返回整数作为最终结果。
(图片来源于leetcode)
这里我们需要读取符号,具体数字,数字前面还不能有0,这里我们可用设置正则化规则进行匹配
import re
class Solution:
def myAtoi(self, str: str) -> int:
INT_MAX = 2147483647
INT_MIN = -2147483648
str = str.lstrip() #清除左边多余的空格
num_re = re.compile(r'^[\+\-]?\d+') #设置正则规则
num = num_re.findall(str)
num = int(*num)
return max(min(num,INT_MAX),INT_MIN)
我们这里设置的正则化规则为首先
^ 表示匹配字符串的开头。
[\+\-]? 表示可选的正号或负号。
\d+ 表示一个或多个数字。
findall 方法返回所有匹配的结果,通常是一个列表。先解包列表,再强制类型转换得到最终结果。
给定一个字符串 s
,返回 s
是否是一个 有效数字。
例如,下面的都是有效数字:"2", "0089", "-0.1", "+3.14", "4.", "-.9", "2e10", "-90E3", "3e+7", "+6e-1", "53.5e93", "-123.456e789"
,而接下来的不是:"abc", "1a", "1e", "e3", "99e2.5", "--6", "-+3", "95a54e53"
。
一般的,一个 有效数字 可以用以下的规则之一定义:
- 一个 整数 后面跟着一个 可选指数。
- 一个 十进制数 后面跟着一个 可选指数。
一个 整数 定义为一个 可选符号 '-'
或 '+'
后面跟着 数字。
一个 十进制数 定义为一个 可选符号 '-'
或 '+'
后面跟着下述规则:
- 数字 后跟着一个 小数点
.
。 - 数字 后跟着一个 小数点
.
再跟着 数位。 - 一个 小数点
.
后跟着 数位。
指数 定义为指数符号 'e'
或 'E'
,后面跟着一个 整数。
数字 定义为一个或多个数位。
我们这里需要匹配实数以及相对复杂的指数,这里我们就可以分为两种情况,第一种情况分为两小种情况,一是整数二是小数,第二种情况则是指数,我们这里就可以直接来写正则化规则了。
class Solution:
def isNumber(self, s: str) -> bool:
pattern = r'^[+-]?(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?$'
res = re.match(pattern,s.strip())
return bool(res)
一、1. ^[+-]?
^:匹配字符串的开头。
[+-]?:匹配可选的正号 + 或负号 -。? 表示前面的字符或组可以出现 0 次或 1 次。但不是多次
2. (\d+(\.\d*)?|\.\d+)
(\d+(\.\d*)?|\.\d+):这是一个分组,匹配整数或小数部分。
\d+:匹配一个或多个数字。
(\.\d*)?:匹配可选的小数部分。\. 匹配点号,\d* 匹配 0 个或多个数字。? 表示小数部分可以出现 0 次或 1 次。
|\.\d+:匹配以点号开头的小数部分。\. 匹配点号,\d+ 匹配一个或多个数字。
|:表示“或”,匹配前面或后面的表达式。
二、 ([eE][+-]?\d+)?
([eE][+-]?\d+)?:这是一个分组,匹配可选的指数部分。
[eE]:匹配小写或大写的 e,表示指数部分的开始。
[+-]?:匹配可选的正号 + 或负号 -。
\d+:匹配一个或多个数字。
?:表示指数部分可以出现 0 次或 1 次。
三、 $没什么好说的,就是匹配结尾
以上都是些简单情景,如果需要匹配复杂的任务需要设计复杂的匹配规则。