零门槛掌握正则表达式--超硬核!【建议收藏】

前言

正则表达式几乎可以在所有语言中使用,不管前端JavaScript,还是后端Java、Python、c#等,都提供相应的接口/函数支持正则表达式。

没学正则表达式之前,我们只能看着正则大师们写了一串外星文似的字符串,完全不懂具体什么含义,但是却可以替换我们的一大串if else逻辑数据校验。

今天我们就用最通俗的语言讲述正则中的基本知识,一起揭开正则表达式神秘的面纱!

在这里插入图片描述

1. 正则表达式介绍

正则表达式 :一组由字母和符号组成的特殊文本,可以帮助我们从某个复杂的字符串中,提取出满足我们要求的特殊文本。

实际开发过程中经常会有查找符合某些复杂规则的字符串的需要,比如:邮箱、图片地址、手机号码等,这时候想匹配或者查找符合某些规则的字符串就可以使用正则表达式了。

2. re模块介绍

本文通过python中正则进行举例测试。首先python中使用正则表达式需要导入模块re。

注:re.match() 根据正则表达式从头开始匹配字符串数据,如果如果开头没有匹配上,则会报错。下面案例都会使用match进行匹配,方便讲解。

re模块的介绍

在Python中需要通过正则表达式对字符串进行匹配的时候,可以使用一个 re 模块。

# 导入re模块
import re

# 使用match方法进行匹配操作
result = re.match(正则表达式,要匹配的字符串)

# 如果上一步匹配到数据的话,可以使用group方法来提取数据
result.group()

re模块的使用

import re


# 使用match方法进行匹配操作
result = re.match("csdn","csdn.net")
# 获取匹配结果
info = result.group()
print(info)
# csdn

正则表达式之所以这么强大,是因为拥有很多专用的操作符(又称“元字符”)、特殊字符和修饰符。

为了更加方便记忆和学习正则表达式,我将这些分成了匹配单个字符、匹配多个字符、匹配开头结尾、匹配分组来分别讲解。

3. 匹配单个字符

代码 功能
. 匹配任意1个字符(除了换行符\n)
[ ] 匹配[ ]中列举的字符
\d 匹配数字,即0-9
\D 匹配非数字,即不是数字
\s 匹配空白,即 空格,tab键
\S 匹配非空白
\w 匹配非特殊字符,即a-z、A-Z、0-9、_、汉字
\W 匹配特殊字符,即非字母、非数字、非汉字

示例1: .

import re
# .	匹配任意1个字符(除了\n)
# 1. 正则表达式
# 2. 要匹配的字符串
# match_obj返回匹配对象
ret = re.match(".","M")
print(ret.group())

ret = re.match("t.o","too")
print(ret.group())

ret = re.match("t.o","two")
print(ret.group())

match_obj = re.match("t.o", "t\no")
if match_obj:
    # 获取匹配结果
    result = match_obj.group()
    print(result)
else:
    # 匹配失败match_obj是一个None
    print("匹配失败")

运行结果:

M
too
two
匹配失败

示例2:[]

import re
# 1. 正则表达式
# 2. 要匹配的字符串
# match_obj返回匹配对象
# [ ]	匹配[ ]中列举的字符

# 如果hello的首字符小写,那么正则表达式需要小写的h
ret = re.match("h","hello Python") 
print(ret.group())

# 如果hello的首字符大写,那么正则表达式需要大写的H
ret = re.match("H","Hello Python") 
print(ret.group())

match_obj = re.match("葫芦娃[12]", "葫芦娃1")
if match_obj:
    # 获取匹配结果
    result = match_obj.group()
    print(result)
else:
    # 匹配失败match_obj是一个None
    print("匹配失败")

# 匹配银行卡密码中的其中一位
match_obj = re.match("[0123456789]", "7")
if match_obj:
    # 获取匹配结果
    result = match_obj.group()
    print(result)
else:
    # 匹配失败match_obj是一个None
    print("匹配失败")

match_obj = re.match("[0-9]", "7")
if match_obj:
    # 获取匹配结果
    result = match_obj.group()
    print(result)
else:
    # 匹配失败match_obj是一个None
    print("匹配失败")

运行结果:

h
H
葫芦娃1
7
7

示例3:\d

# \d = > [0-9]= >[0123456789]
match_obj = re.match("\d", "7")
if match_obj:
    # 获取匹配结果
    result = match_obj.group()
    print(result)
else:
    # 匹配失败match_obj是一个None
    print("匹配失败")

运行结果:

7

示例4:\D

# \D: 匹配一个非数字字符
match_obj = re.match("\D", "a")
if match_obj:
    # 获取匹配结果
    result = match_obj.group()
    print(result)
else:
    # 匹配失败match_obj是一个None
    print("匹配失败")

运行结果:

a

示例5:\s

# \s: 匹配一个空白字符,空格或者tab键
match_obj = re.match("葫芦娃\s[12]", "葫芦娃 1")
if match_obj:
    # 获取匹配结果
    result = match_obj.group()
    print(result)
else:
    # 匹配失败match_obj是一个None
    print("匹配失败")

运行结果:

葫芦娃 1

示例6:\S

match_obj = re.match("葫芦娃\S[12]", "葫芦娃+1")
if match_obj:
    # 获取匹配结果
    result = match_obj.group()
    print("没空白的匹配:", result)
else:
    # 匹配失败match_obj是一个None
    print("没空白的匹配:匹配失败")

运行结果:

没空白的匹配: 葫芦娃+1

示例7:\w

# \w: 匹配一个字母、数字、下划线、汉字
match_obj = re.match("\w", "哈")
if match_obj:
    # 获取匹配结果
    result = match_obj.group()
    print(result)
else:
    # 匹配失败match_obj是一个None
    print("匹配失败")

运行结果:

示例8:\W

# 匹配特殊字符中的一位
match_obj = re.match("\W", "&")
if match_obj:
    # 获取匹配结果
    print(match_obj.group())
else:
    print("匹配失败")

运行结果:

&

4. 匹配多个字符

代码 功能
* 匹配前一个字符出现0次或者无限次,即可有可无
+ 匹配前一个字符出现1次或者无限次,即至少有1次
? 匹配前一个字符出现1次或者0次,即要么有1次,要么没有
{m} 匹配前一个字符出现m次
{m,n} 匹配前一个字符出现从m到n次

示例1:*

需求:匹配出一个字符串第一个字母为大小字符,后面都是小写字母并且这些小写字母可 有可无

# *	匹配前一个字符出现0次或者无限次,即可有可无
import re

ret = re.match("[A-Z][a-z]*","M")
print(ret.group())

ret = re.match("[A-Z][a-z]*","MnnM")
print(ret.group())

ret = re.match("[A-Z][a-z]*","Aabcdef")
print(ret.group())

运行结果:

M
Mnn
Aabcdef

示例2:+

需求:匹配一个字符串,第一个字符是t,最后一个字符串是o,中间至少有一个字符

import re


match_obj = re.match("t.+o", "two")
if match_obj:
    print(match_obj.group())
else:
    print("匹配失败")

运行结果:

two

示例3:?

需求:匹配出这样的数据,但是https 这个s可能有,也可能是http 这个s没有

match_obj = re.match("https?", "http")
if match_obj:
    print(match_obj.group())
else:
    print("匹配失败")

运行结果:

http

示例4:{m}

# {m}: 匹配前一个字符串必须出现m次
match_obj = re.match("ht{2}p", "http")
if match_obj:
    # 获取匹配结果
    result = match_obj.group()
    print(result)
else:
    print("匹配失败")

运行结果:

http

示例5:{m,n}

# {m, n}: 匹配前一个字符串最少出现m次,最多出现n次
match_obj = re.match("ht{1,3}p", "httttp")
if match_obj:
    # 获取匹配结果
    result = match_obj.group()
    print(result)
else:
    print("匹配失败")

# 扩展: {m, }:匹配前一个字符串至少出现m次
match_obj = re.match("ht{2,}p", "htttttp")
if match_obj:
    # 获取匹配结果
    result = match_obj.group()
    print(result)
else:
    print("匹配失败")

运行结果:

匹配失败
htttttp

5. 匹配开头和结尾

代码 功能
^ 匹配字符串开头, [^指定字符]: 表示除了指定字符都匹配
$ 匹配字符串结尾

示例1:^

# 匹配以数字开头
match_obj = re.match("^\d.*", "1abc")
if match_obj:
    # 获取匹配结果
    result = match_obj.group()
    print(result)
else:
    print("匹配失败")

运行结果:

1abc

示例2:$

match_obj = re.match(".*\d$", "aa3")
if match_obj:
    # 获取匹配结果
    result = match_obj.group()
    print(result)
else:
    print("匹配失败")

运行结果:

aa3

示例3:^ 和 $

# 匹配以数字开头中间内容不管以数字结尾
match_obj = re.match("^\d.*\d$", "2asdfa3")
if match_obj:
    # 获取匹配结果
    result = match_obj.group()
    print(result)
else:
    print("匹配失败")

# [^指定字符] 表示除了指定字符都匹配

# [^47] 除了4和7都匹配
# ^: 表示以指定字符串开头
# [^]: 表示除了指定字符串都匹配
match_obj = re.match("^\d.*[^47]$", "2asdfa7")
if match_obj:
    # 获取匹配结果
    result = match_obj.group()
    print(result)
else:
    print("匹配失败")

运行结果:

2asdfa3
匹配失败

6. 匹配分组

代码 功能
| 匹配左右任意一个表达式
(ab) 将括号中字符作为一个分组
\num 引用分组num匹配到的字符串
(?P) 分组起别名
(?P=name) 引用别名为name分组匹配到的字符串

示例1:|

# 水果列表
fruit_list = ['apple', 'banana', 'orage', 'pear', 'peach']

for value in fruit_list:
    # 根据每一个字符串,使用正则表达式进行匹配
    # |	匹配左右任意一个表达式
    match_obj = re.match("banana|pear", value)

    if match_obj:
        result = match_obj.group()
        print("我想吃的水果:", result)
    else:
        print("我不想吃的水果:", value)

运行结果:

我不想吃的水果: apple
我想吃的水果: banana
我不想吃的水果: orage
我想吃的水果: pear
我不想吃的水果: peach

示例2:( )

# 匹配出163、126、qq等邮箱
# \.: 表示对正则表达式里面的.进行了转义,变成了一个普通点,只能匹配.字符
# (163|126|qq) 表示一个分组,出现一个小括号就表示一个分组,分组是从1开始的
# 如果出现多个小括号,分组的顺序是从左到右一次排序
match_obj = re.match("[a-zA-Z0-9_]{4,20}@(163|126|qq)\.com", "[email protected]")
if match_obj:
    # 获取整个匹配的数据,如果使用分组数的化,默认是0
    result = match_obj.group(0)
    # 获取匹配分组数据
    type = match_obj.group(1)
    print(type)
    print(result)
else:
    print("匹配失败")

# "qq:3014587"
match_obj = re.match("(qq:)([1-9]\d{4,11})", "qq:666666")
if match_obj:

    result = match_obj.group()
    print(result)

    result = match_obj.group(1)
    print(result)

    result = match_obj.group(2)
    print(result)
else:
    print("匹配失败")

运行结果:

163
hello@163.com
qq:666666
qq:
666666

示例3:\num

需求:匹配出hh

match_obj = re.match("<[a-zA-Z1-6]+>.*</[a-zA-Z1-6]+>", "<html>hh</div>")

if match_obj:
    print(match_obj.group())
else:
    print("匹配失败")

match_obj = re.match("<([a-zA-Z1-6]+)>.*</\\1>", "<html>hh</html>")

if match_obj:
    print(match_obj.group())
else:
    print("匹配失败")

运行结果:

<html>hh</div>
<html>hh</html>

需求:匹配出 <html><h1>www.baidu.com</h1></html>

match_obj = re.match("<([a-zA-Z1-6]+)><([a-zA-Z1-6]+)>.*</\\2></\\1>", "<html><h1>www.baidu.com</h1></html>")

if match_obj:
    print(match_obj.group())
else:
    print("匹配失败")

运行结果:

<html>\<h1>www.baidu.com\</h1>\</html>

示例4:(?P) (?P=name)

# <html><h1>www.itcast.cn</h1></html>

match_obj = re.match("<(?P<name1>[a-zA-Z1-6]+)><(?P<name2>[a-zA-Z1-6]+)>.*</(?P=name2)></(?P=name1)>", "<html><h1>www.baidu.com</h1></html>")
if match_obj:

    result = match_obj.group()
    print(result)
else:
    print("匹配失败")

运行结果:

<html><h1>www.baidu.com</h1></html>

7. python中常用方法介绍

三个函数用于查找匹配match()、search()、findall(),一个函数sub()用于替换,一个函数split()用于切分字符串。

  • match():匹配字符串的开头,如果开头匹配不上,则返回None;
  • search():扫描整个字符串,匹配后立即返回,不在往后面匹配;
  • findall():扫描整个字符串,以列表形式返回所有的匹配值;
  • compile():将字符串编译成正则表达式对象,供 match() 、 search() 和findall()函数使用;
  • sub():扫描整个字符串,用于替换字符串的某些值;
  • split():扫描整个字符串,按照指定分隔符切分字符串;
s1 = 'ab少cd年abc'
r2 = re.search('b',s1)
r2.group()
# b

r3 = re.findall('[a|b]',s1)
r3.group()
# ['a', 'b', 'a', 'b']

r4 = re.findall('f',s1)
r4.group()
# []

下面我们根据一个爬虫经常见到的html格式数据,使用正则表达式,获取其中的li标签,或者获取其中的href属性,应该怎么做呢?

html = '''<html>
<head lang="en">
<title>Title</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
   <div id="content">
       <ul id="ul1">
           <li>first</li>
           <li>second</li>
           <li>third</li>
       </ul>
       <ul id="ul2">
           <li>alpha</li>
           <li>beta</li>
       </ul>
    </div>
    <div id="url">
        <a href="http:www.baidu.com" title="baidu">baidu</a>
        <a href="http:www.csdn.net" title="csdn">csdn</a>
    </div>
</body>
</html>
'''
# 获取li标签
re.findall('<li>(.*?)</li>',html)
# ['first', 'second', 'third', 'alpha', 'beta']

# 获取href属性
re.findall('<a href="(.*?)" ',html)
# ['http:www.baidu.com', 'http:www.csdn.net']

操作其实很简单,固定写法:首尾照抄字符串源代码,我们想要的东西使用()小括号,括起来,里面写上 .*?

上面提到了一个.与.?,其中.表示贪婪匹配,.?表示非贪婪匹配。

  • . 可以匹配除了换行符以外的所有字符;
  • *表示匹配前面的字符无限次;
  • ?前面紧挨的元素,最多匹配一次;
# '\D{3,5}'表示匹配非数字3-5次。
s3 = '12one34two56three78four'
# 这里没有指定最大匹配次数,因此默认会替换所有的匹配值
re.sub('\D{3,5}','字母',s3)
# 12字母34字母56字母78字母

# 这里指定最大匹配次数count=2,因此只会替换前2个匹配值
re.sub('\D{3,5}','字母',s3,2)
# 12字母34字母56three78four

# 如果count=3,则会替换3个匹配值
re.sub('\D{3,5}','字母',s3,3)
# 12字母34字母56字母78four

# '\D'表示匹配非数字
s4 = '136-3456-7413'
# 这里如果不指定“最大分割次数”,则是不限次数切分
re.split('\D',s4)
# ['136', '3456', '7413']

# 如果指定最大分割次数maxsplit=1,那么就只以第一个分隔符,进行切分
re.split('\D',s4,1)
# ['136', '3456-7413']

好了,今天就到这里,明天我们继续努力!
在这里插入图片描述

创作不易,白嫖不好,各位的支持和认可,就是我创作的最大动力,我们下篇文章见!

Dragon少年 | 文

如果本篇博客有任何错误,请批评指教,不胜感激 !

猜你喜欢

转载自blog.csdn.net/hhladminhhl/article/details/117715187