正则表达式

正则表达式在线测试工具:https://regex101.com/

正则表达式在线测试工具:https://regex101.com/

简短:https://www.bilibili.com/video/BV1da4y1p7iZ

教程:https://deerchao.cn/tutorials/regex/regex.htm

限定符

匹配‘?’前一个或者0个字符(可选)
*匹配‘*****’前零个或多个字符
+匹配出现一次以上的字符
{}允许我们输入一个范围

{2,6}:出现次数在2到6之间

{2,}:两次以上

{2}:出现两次

使用()括起来可以使用限定符对多个字符限定

或运算

(cat|dog)匹配cat或者dog

括号必不可少

字符类

[abc]:要求匹配的字符只能取自他们

[a-z]:也可以指定字符范围

[a-zA-Z0-9]

方括号前面写一个^则要求除了方括号以外的字符

[^0-9]:非数字符号

[aeiou]
[.?!]匹配标点符号(.或?或!)。

元字符

正则表达式为我们预先定义好了一系列常用的字符类型:数字、空白符、单词开头、结尾等等,他们被称为元字符都是以\开头

\d数字字符
\w单词字符(单词、数字、下划线)
\s空白符(空白符,tab, 换行符)
\D非数字字符
\W非单词字符
\S非空白字符
.任意字符,但不包含换行符
^匹配行首(字符串的开头)
$匹配行尾(字符串的结尾)
\b单词边界

^a匹配行首的a

a$匹配行尾的a

贪婪与懒惰匹配

默认匹配模式是贪婪匹配,会尽可能多的字符

表示懒惰匹配,会尽可能匹配少的字符

.+   //贪婪
.+?  //懒惰

转义

要匹配.则需要转义,\.、或者使用[.]

\-
\\
\.
\?

分组

在正则表达式中还提供了一种将表达式分组的机制,当使用分组时,除了获得整个匹配。还能够在匹配中选择每一个分组。

要实现分组很简单,使用()即可。

分组有一个非常重要的功能——捕获数据。所以()被称为捕获分组,用来捕获数据,当我们想要从匹配好的数据中提取关键数据的时候可以使用分组。

  • 分组0对应整个正则表达式
  • 实际上组号分配过程是要从左向右扫描两遍的:第一遍只给未命名组分配,第二遍只给命名组分配--因此所有命名组的组号都大于未命名的组号
  • 你可以使用(?:exp)这样的语法来剥夺一个分组对组号分配的参与权.
<div>(.*?)</div>:就能提取div标签里的元素

有时候,我们并不需要捕获某个分组的内容,但是又想使用分组的特性。

这个时候就可以使用非捕获组(?:表达式),从而不捕获数据,还能使用分组的功能。

例如想要匹配两个字母组成的单词或者四个字母组成的单词就可以使用非捕获分组

\b(?:\w{2}|\w{4})\b

回溯引用

要匹配一段 HTML 代码,比如:0123<font>提示</font>abcd,可能会编写出这样一段正则表达式:

<\w+>.*?*</\w+>

这确实可以匹配,不过可能还有另一种情况,如果数据改成这样:<font>提示</bar>

可以使用分组的回溯引用,使用\N可以引用编号为N的分组,因此上述例子的代码我们可以改为:

<\w+>.*?*</\1>

通过这个例子,可以发现 \1 表示的就是第一个分组,在这里第一个分组匹配的是 font 所以\1 就代表font

你也可以自己指定子表达式的组名。要指定一个子表达式的组名,请使用这样的语法:(?<Word>\w+)(或者把尖括号换成’也行:(?'Word'\w+)),这样就把\w+的组名指定为Word了。要反向引用这个分组捕获的内容,你可以使用\k<Word>,所以上一个例子也可以写成这样:\b(?<Word>\w+)\b\s+\k<Word>\b

先行断言

很多人也称先行断言和后行断言为环视,也有人叫预搜索,其实叫什么无所谓,重要的是知道如何使用它们!

先行断言和后行断言总共有四种:

  1. 正向先行断言
  2. 反向先行断言
  3. 正向后行断言
  4. 反向后行断言

正向先行断言:

(?=表达式),指在某个位置向右看,表示所在位置右侧必须能匹配表达式

例如:

我喜欢你 我喜欢 我喜欢我 喜欢 喜欢你

如果要取出喜欢两个字,要求这个喜欢后面有你,这个时候就要这么写:喜欢(?=你),这就是正向先行断言

提取包含大小写字母的字符串:

先行断言可以用来判断字符串是否符合特定的规则,例如提取包含至少一个大小写字母的字符串:

(?=.*?[a-z])(?=.*?[A-Z]).+

反向先行断言

(?!表达式)的作用是保证右边不能出现某字符。

例如: 我喜欢你 我喜欢 我喜欢我 喜欢 喜欢你

如果要取出喜欢两个字,要求这个喜欢后面没有你,这个时候就要这么写:喜欢(?!你),这就是反向先行断言

正向后行断言


本小节只需要你记住一句话:先行断言和后行断言只有一个区别,即先行断言从左往右看,后行断言从右往左看。

正向后行断言:(?<=表达式),指在某个位置向左看,表示所在位置左侧必须能匹配表达式

例如:如果要取出喜欢两个字,要求喜欢的前面有我后面有你,这个时候就要这么写:(?<=我)喜欢(?=你)

反向后行断言:

(?<!表达式),指在某个位置向左看,表示所在位置左侧不能匹配表达式

例如:如果要取出喜欢两个字,要求喜欢的前面没有我后面没有你,这个时候就要这么写:(?<!我)喜欢(?!你)。.

Pyhton的re模块

1、查找

  • search只返回一个Match
  • match从头开始匹配Match
  • findall返回字符串
  • finditer返回Match迭代器

Match对象包含很多信息,比如是第几个字符到第几个字符

Match对象有group方法,可以得到完整的匹配对象

python
text = r"aaabbbcccddd"
res = re.search("a{3}b{3}", text)
print(res.group())#--->aaabbb

text = r"aaabbbcccddd"
res = re.search(r"(a{3})(b{3})", text)
print(res.group())#--->aaabbb

里面可以填参数可以获取特定分组信息

python
#分组0对应整个正则表达式
res = re.search(r"(a{3})(b{3})c{3}", text)
print(res.group(0))#aaabbbccc
print(res.group(1))#aaa
print(res.group(2))#bbb

groups()得到元组

print(res.groups())
('aaa', 'bbb')

搜索的时候可以传入flags参数,指定一些东西

#re.I	不区分大小写
res = re.search(r"(a{3})(b{3})c{3}", text,flags=re.I)
Flag功能示例
re.IGNORECASE (或 re.I)忽略大小写re.findall(r"abc", "Abc") 返回 ['Abc']
re.LOCALE (或 re.L)使用当前区域设置re.findall(r"\d+", "123") 返回 ['123']
re.MULTILINE (或 re.M)多行模式,^和$匹配每一行的开始和结束re.findall(r"^abc$", "abc\nabc") 返回 ['abc', 'abc']
re.DOTALL (或 re.S)使.匹配包括换行符在内的任意字符re.findall(r"abc.", "abc\n") 返回 ['abc\n']
re.VERBOSE (或 re.X)忽略空白字符,并允许在正则表达式中添加注释re.findall(r"abc # comment\n", "abc") 返回 ['abc']
re.UNICODE (或 re.U)使用Unicode字符集re.findall(r"\w+", "你好世界") 返回 ['你好', '世界']
re.TEMPLATE用于re.sub(),只替换第一个匹配项re.sub(r"abc", "xyz", "abcabc", count=1) 返回 "xyzabc"

使用方式

  • 可以单独使用,例如 re.findall(r"abc", "Abc", re.IGNORECASE)
  • 可以组合使用,例如 re.findall(r"abc", "Abc\nabc", re.IGNORECASE | re.MULTILINE)

2、替换

  • sub替换,返回替换完的字符串
  • subn替换完之后我们一共有几个字符被替换掉了

3、分割

  • spilt用一些字符来做分割

4、compile把正则表达式变成可传达的对象

一般用于同一个正则被调用多次

python
def compile(pattern, flags=0):
    "Compile a regular expression pattern, returning a Pattern object."
#编译一个正则表达式模式,返回一个pattern对象。
a = re.compile("xaz")
a.match(text)
#可以直接调用

评论

评论加载中……