正则

发布时间 2023-12-26 13:37:11作者: ssrheart

【一】正则

(1)引入

  • 在线测试工具 http://tool.chinaz.com/regex/

  • 首先要知道的是

    • 谈到正则,就只和字符串相关了。
    • 在提供的工具中,输入的每一个字都是一个字符串。

(2)字符组

  • 字符组 :[] 在同一个位置可能出现的各种字符组成了一个字符组
  • 在正则表达式中用[]表示
  • 字符分为很多类
    • 比如数字、字母、标点等等。
  • 假如你现在要求一个位置"只能出现一个数字"
  • 那么这个位置上的字符只能是0、1、2...9这10个数之一。
正则 待匹配字符 匹配结果 说明
[0123456789] 8 True 在一个字符组里枚举合法的所有字符,字符组里的任意一个字符和"待匹配字符"相同都视为可以匹配
[0123456789] a False 由于字符组中没有"a"字符,所以不能匹配
[0-9] 7 True 也可以用-表示范围,[0-9]就和[0123456789]是一个意思
[a-z] s True 同样的如果要匹配所有的小写字母,直接用[a-z]就可以表示
[A-Z] B True [A-Z]就表示所有的大写字母
[0-9a-fA-F] e True 可以匹配数字,大小写形式的a~f,用来验证十六进制字符

(3)元字符

元字符 匹配内容
. 匹配除换行符以外的任意字符
\w 匹配字母或数字或下划线
\s 匹配任意的空白符
\d 匹配数字
\n 匹配一个换行符
\t 匹配一个制表符
\b 匹配一个单词的结尾
^ 匹配字符串的开始
$ 匹配字符串的结尾
\W 匹配非字母或数字或下划线
\D 匹配非数字
\S 匹配非空白符
a|b 匹配字符a或字符b
() 匹配括号内的表达式,也表示一个组
[...] 匹配字符组中的字符
[^...] 匹配除了字符组中字符的所有字符

(4)量词

  • *相当于
  • +相当于
  • ?相当于
量词 用法说明
* 重复零次或多次
+ 重复一次或多次
? 重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次

(5)位置元字符. ^ $

正则 待匹配字符 匹配 结果 说明
钱. 钱一钱二钱三 钱一钱二钱三 匹配所有"钱."的字符
^钱. 钱一钱二钱三 钱一 只从开头匹配"钱."
`钱. 正则 待匹配字符 匹配 结果
------ ------------ ------------ -------------------
钱. 钱一钱二钱三 钱一钱二钱三 匹配所有"钱."的字符
^钱. 钱一钱二钱三 钱一 只从开头匹配"钱."
| 钱一钱二钱三 | 钱三 | 只匹配结尾的"钱.$"

(6)重复匹配\* + ? { }

  • 前面的*,+,?等都是贪婪匹配,也就是尽可能匹配,后面加?号使其变成惰性匹配
正则 待匹配字符 匹配 结果 说明
钱.? 钱大和钱二和钱多多 钱大 钱二 钱多 ?表示重复零次或一次,即只匹配"李"后面一个任意字符
钱.* 钱大和钱二和钱多多 钱大和钱二和钱多多 *表示重复零次或多次,即匹配"李"后面0或多个任意字符
钱.+ 钱大和钱二和钱多多 钱大和钱二和钱多多 +表示重复一次或多次,即只匹配"李"后面1个或多个任意字符
钱.{1,2} 钱大和钱二和钱多多 钱大和 钱二和 钱多多 {1,2}匹配1到2次任意字符

(7)字符集[][^]

正则 待匹配字符 匹配 结果 说明
钱[大钱二和钱多多]* 钱大和钱二和钱多多 钱大和钱二和钱多多 表示匹配"钱"字后面[大钱二和钱多多]的字符任意次
钱[^和]* 钱大和钱二和钱多多 钱大 钱二 钱多多 表示匹配一个不是"和"的字符任意次
[\d] 123qazwsx233 1 2 3 2 3 3 表示匹配任意一个数字,匹配到6个结果
[\d]+ 123qazwsx233 123 233 表示匹配任意个数字,匹配到2个结果

(8)分组匹配 ()与 或 |[^]

  • 身份证号码是一个长度为15或18个字符的字符串
    • 如果是15位则全部有数字组成,首位不能为0;
    • 如果是18位,则前17位全部是数字,末位可能是数字或x,
    • 下面我们尝试用正则来表示:
正则 待匹配字符 匹配 结果 说明
`[1]\d{13,16}[0-9x] 正则 待匹配字符 匹配 结果
----------------------------- ------------------ ------------------ ------------------------------------------------------------
  | 110101198001017032 | 110101198001017032 | 表示可以匹配一个正确的身份证号                               |

| ^[1-9]\d{13,16}[0-9x]| 正则 | 待匹配字符 | 匹配 结果 | 说明 | | ----------------------------- | ------------------ | ------------------ | ------------------------------------------------------------ | | 1101011980010170 | 1101011980010170 | 表示也可以匹配这串数字,但这并不是一个正确的身份证号码,它是一个16位的数字 | | [2]\d{14}(\d{2}[0-9x])?| 正则 | 待匹配字符 | 匹配 结果 | 说明 |
| ----------------------------- | ------------------ | ------------------ | ------------------------------------------------------------ |
| 1101011980010170 | False | `现在不会匹配错误的身份证号了 ()表示分组,将\d{2}[0-9x]分成一组,就可以整体约束他们出现的次数为0-1次` |
| `^([1-9]\d{16}[0-9x] | [1-9]\d{14})| 正则 | 待匹配字符 | 匹配 结果 | 说明 |
| ----------------------------- | ------------------ | ------------------ | ------------------------------------------------------------ |
| 110105199812067023 | 110105199812067023 |

(9)转义符 \

  • 在正则表达式中,有很多有特殊意义的是元字符
    • 比如\n和\s等
    • 如果要在正则中匹配正常的"\n"而不是"换行符"就需要对""进行转义,变成''。
  • 在python中,无论是正则表达式,还是待匹配的内容,都是以字符串的形式出现的,在字符串中\也有特殊的含义,本身还需要转义。
  • 所以如果匹配一次"\n",字符串中要写成'\n',那么正则里就要写成"\n",这样就太麻烦了。
  • 这个时候就用到了r'\n'这个概念,此时的正则是r'\n'就可以了。
正则 待匹配字符 匹配 结果 说明
\n \n False 因为在正则表达式中\是有特殊意义的字符,所以要匹配\n本身,用表达式\n无法匹配
\n \n True 转义\之后变成\,即可匹配
"\n" '\n' True 如果在python中,字符串中的''也需要转义,所以每一个字符串''又需要转义一次
r'\n' r'\n' True 在字符串之前加r,让整个字符串不转义

(10)贪婪匹配

  • 贪婪匹配:在满足匹配时,匹配尽可能长的字符串,默认情况下,采用贪婪匹配
正则 待匹配字符 匹配 结果 说明
<.*> <script>...<script> <script>...<script> 默认为贪婪匹配模式,会匹配尽量长的字符串
<.*?> r'\d' <script> <script> 加上?为将贪婪匹配模式转为非贪婪匹配模式,会匹配尽量短的字符串
  • 几个常用的非贪婪匹配,Pattern
  • *? 重复任意次,但尽可能少重复
  • +? 重复1次或更多次,但尽可能少重复
  • ?? 重复0次或1次,但尽可能少重复
  • {n,m}? 重复n到m次,但尽可能少重复
  • {n,}? 重复n次以上,但尽可能少重复

(11)

  • . 是任意字符
  • * 是取 0 至 无限长度
  • ? 是非贪婪模式。
  • 合在一起就是取尽量少的任意字符,一般不会这么单独写
    • 他大多用在:.*? 就是取前面任意长度的字符,直到一个x出现

【二】re模块常用方法

(1)导入模块

import re

(2)查找结果(findall)

  • 当使用 re.findall 时,它会搜索整个字符串,找到所有匹配正则表达式模式的非重叠部分,并将它们作为一个列表返回。这个函数返回的是所有匹配的字符串列表,而不仅仅是第一个匹配项。

  • findall(pattern正则表达式,string待匹配内容,flags=0)

import re


namestr='my name is heart,my age is 18'
res = re.findall(pattern=r'\d',string=namestr)
print(res)

(3)编译正则表达式(compile)

  • re.compile 是 Python 中 re 模块的一个函数,用于将正则表达式的字符串形式编译成一个可重复使用的正则表达式对象。这个对象可以被用于多次的匹配操作,从而提高效率,尤其是在需要多次使用同一模式的情况下。
import re

name_str = 'my name is heart,my age is 18'
re_type = re.compile(pattern=r'\w')
res_one = re.findall(pattern=re_type,string=name_str)
print(res_one) # ['m', 'y', 'n', 'a', 'm', 'e', 'i', 's', 'h', 'e', 'a', 'r', 't', 'm', 'y', 'a', 'g', 'e', 'i', 's', '1', '8']

(4)查找结果(search)

  • re.search 是 Python 中 re 模块提供的一个函数,用于在字符串中搜索第一个匹配给定正则表达式模式的位置。如果找到匹配项,它返回一个包含匹配信息的 re.Match 对象;如果没有找到匹配项,返回 None

  • 在例子中,字符串'my name is heart, my age is 18'中的第一个字符是 'm',而正则表达式模式\w匹配字母、数字或下划线,因此匹配到了 'm'。所以,res_three的输出是 'm'。group匹配第一个匹配到的字符。

import re

name_str = 'my name is heart,my age is 18'
re_type = re.compile(pattern=r'\w')
res_two = re.search(pattern=re_type,string=name_str)
res_three = re.search(pattern=re_type,string=name_str).group()
print(res_two) # <re.Match object; span=(0, 1), match='m'>
print(res_three) # m

(5)findall和search的区别

re.findallre.search 是 Python 中 re 模块提供的两个不同的正则表达式匹配函数,它们有以下区别:

  1. 返回类型:
    • re.findall: 返回一个包含所有匹配项的列表。如果没有找到匹配项,返回空列表 []
    • re.search: 返回第一个匹配项的 re.Match 对象。如果没有找到匹配项,返回 None
  2. 匹配范围:
    • re.findall: 在整个字符串中搜索,找到所有匹配项,并将它们以列表的形式返回。
    • re.search: 在整个字符串中搜索,找到第一个匹配项就停止搜索,并返回一个 re.Match 对象。
  3. 使用场景:
    • re.findall: 适用于需要找到字符串中所有匹配项的情况,例如提取所有的数字、单词等。
    • re.search: 适用于只关心第一个匹配项的情况,或者在整个字符串中找到一个匹配项就足够的情况。

(6)查找结果(match)

  • re.match 是 Python 中 re 模块提供的一个函数,用于检查一个字符串是否以指定的正则表达式模式开头。如果匹配成功,它返回一个表示匹配的 re.Match 对象;如果匹配失败,则返回 None
import re

name_str = 'my name is heart,my age is 18'
re_type = re.compile(pattern=r'\w')
res_one = re.match(pattern=re_type, string=name_str)
res_two = re.match(pattern=re_type, string=name_str).group()
print(res_one) # <re.Match object; span=(0, 1), match='m'>
print(res_two) # m

(7)切割(split)

  • re.split 是 Python 中 re 模块提供的一个函数,用于根据正则表达式模式将字符串分割成一个列表。它的使用方式类似于字符串的 split 方法,但是可以使用更复杂的分隔符模式。
import re

name_str = 'abcd'
res_one = re.split(pattern=r'a',string=name_str)
print(res_one) # ['', 'bcd']

(8)指定个数替换(sub)

  • re.sub 是 Python 中 re 模块提供的一个函数,用于在字符串中搜索正则表达式模式,并将匹配的部分替换为指定的字符串。这个函数允许你通过正则表达式来灵活地搜索和替换字符串中的文本。
import re

name_str = 'age4heart5god6'

# 将数字替换成'H',参数1表示只替换1个
result = re.sub(pattern='\d', repl='D', string=name_str, count=1)
print(result)  # ageDheart5god6

(9)替换全部(subn)

  • re.subn 是 Python 中 re 模块提供的一个函数,与 re.sub 类似,但它返回一个包含替换次数的元组。这个元组的第一个元素是替换后的新字符串,第二个元素是实际进行替换的次数。
import re

name_str = 'age4heart5god6'

# 将数字替换成'H',返回元组(替换的结果,替换了多少次)
result = re.subn(pattern='\d',repl= 'H', string=name_str)
print(result) # ('ageHheartHgodH', 3)

(10)匹配结果为迭代器(finditer)

  • re.finditer 是 Python 中 re 模块提供的一个函数,用于在字符串中搜索所有匹配正则表达式模式的部分。与 re.findall 不同,re.finditer 返回一个迭代器,该迭代器生成所有匹配的 re.Match 对象。
import re

name_str = 'age4heart5god6778'

# finditer返回一个存放匹配结果的迭代器
ret = re.finditer(pattern='\d', string=name_str)
print(ret)
# <callable_iterator object at 0x0000014ED4CD3EE0>
print(next(ret).group()) # 4
# 查看第一个结果
print(next(ret).group()) # 5
# 查看第二个结果
print([i.group() for i in ret]) # ['6', '7', '7', '8']
# 查看剩余的所有结果

【三】正则方法之优先级

(1)findall的优先级查询

import re

res = re.findall(pattern='www.(baidu|bilibili).com', string='www.bilibili.com')
# 这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可
print(res)  # ['bilibili']

(2)split的优先级查询

import re

name_str = 'age4heart5god6'

res = re.split(pattern="\d+", string=name_str)
print(res)  # ['age', 'heart', 'god', '']

res = re.split(pattern="(\d+)", string=name_str)
print(res)  # ['age', '4', 'heart', '5', 'god', '6', '']

image


  1. 1-9 ↩︎

  2. 1-9 ↩︎