自学内容网 自学内容网

正则表达式

语法:用来描述你想搜索的字符串的特征;简单化

正常情况

content = '''
Python3 高级开发工程师 上海互教教育科技有限公司上海-浦东新区2万/月02-18满员
测试开发工程师(C++/python) 上海墨鹍数码科技有限公司上海-浦东新区2.5万/每月02-18未满员
Python3 开发工程师 上海德拓信息技术股份有限公司上海-徐汇区1.3万/每月02-18剩余11人
测试开发工程师(Python) 赫里普(上海)信息科技有限公司上海-浦东新区1.1万/每月02-18剩余5人
Python高级开发工程师 上海行动教育科技股份有限公司上海-闵行区2.8万/月02-18剩余255人
python开发工程师 上海优似腾软件开发有限公司上海-浦东新区2.5万/每月02-18满员
'''

# 将文本内容按行放入列表
lines = content.splitlines()
for line in lines:
    # 查找'万/月' 在 字符串中什么地方
    pos2 = line.find('万/月')
    if pos2 < 0:
        # 没找到就找'万/每月' 在 字符串中什么地方
        pos2 = line.find('万/每月')
        # 都找不到
        if pos2 < 0: 
            continue

    # 执行到这里,说明可以找到薪资关键字
    # 接下来分析 薪资 数字的起始位置
    # 方法是 找到 pos2 前面薪资数字开始的位置
    idx = pos2-1

    # 只要是数字或者小数点,就继续往前面找
    while line[idx].isdigit() or line[idx]=='.':
        idx -= 1

    # 现在 idx 指向 薪资数字前面的那个字,
    # 所以薪资开始的 索引 就是 idx+1
    pos1 = idx + 1

    print(line[pos1:pos2])

使用正则表达式

content = '''
Python3 高级开发工程师 上海互教教育科技有限公司上海-浦东新区2万/月02-18满员
测试开发工程师(C++/python) 上海墨鹍数码科技有限公司上海-浦东新区2.5万/每月02-18未满员
Python3 开发工程师 上海德拓信息技术股份有限公司上海-徐汇区1.3万/每月02-18剩余11人
测试开发工程师(Python) 赫里普(上海)信息科技有限公司上海-浦东新区1.1万/每月02-18剩余5人
Python高级开发工程师 上海行动教育科技股份有限公司上海-闵行区2.8万/月02-18剩余255人
python开发工程师 上海优似腾软件开发有限公司上海-浦东新区2.5万/每月02-18满员
'''

import re
for one in  re.findall(r'([\d.]+)万/每{0,1}月', content):
    print(one)

常见语法

普通字符&汉字直接匹配;特殊字符就有特殊含义

如:. * + ? \ [ ] ^ $ { } | ( )

. 表示匹配除了 换行符 之外的任何 单个 字符

当匹配规则只使用一次用 re.findall

content = '''苹果是绿色的
橙子是橙色的
香蕉是黄色的
乌鸦是黑色的'''

import re

for one in  re.findall('.色',content):
    print(one)

否则用re.compile 产生的正则表达式对象

content = '''苹果是绿色的
橙子是橙色的
香蕉是黄色的
乌鸦是黑色的'''

import re
p = re.compile('.色')
for one in  p.findall(content):
    print(one)

星号

* 表示匹配前面的子表达式任意次,包括0次

例如:abc*de:表示 ab 和 de 之间有任意个数(包括0)c 。

特:".* ":表示匹配一串任意长度的字符串任意次。这个时候必须在“.*”的前后加其他的符号来限定范围,否则得到的结果就是原来的整个字符串

例如:

content = '''苹果,是绿色的
橙子,是橙色的
香蕉,是黄色的
乌鸦,是黑色的
猴子,'''

import re
p = re.compile(r',.*')
for one in  p.findall(content):
    print(one)

加号

+ 表示匹配前面的子表达式一次或多次,不包括0次(至少出现1次)

例如:a+b可以匹配"ab"、“aab”、“aaab"等,但不会匹配单独的"b”

 特:".+ ":与.*不同的是,不包括0次,逗号后没内容的就不选

例如:

content = '''苹果,是绿色的
橙子,是橙色的
香蕉,是黄色的
乌鸦,是黑色的
猴子,'''

import re
p = re.compile(r',.+')
for one in  p.findall(content):
    print(one)

问号

? 表示匹配前面的子表达式0次或1次

例如:a?b可以匹配"b"或者"ab"

花括号

{}表示 前面的字符匹配 指定的次数

例如:油{3} 就表示匹配 连续的 油 字 3次;油{3,4} 就表示匹配 连续的 油 字 至少3次,至多 4 次

一个问题:r''

r''是为了防止字符被转义,也就是原生字符串

''这个形式,字符串里含有\n的话就会被转义成换行符;不想被转义的话就在前加\(r"用的就是这个原理)

>>> s='abc\nabc'
>>> s
'abc\nabc'
>>> print s
abc
abc
>>> s=r'abc\nabc'
>>> s
'abc\\nabc'
>>> print s
abc\nabc

贪婪模式改非贪婪模式

在正则表达式中 "*"、 "+"、"?"都是贪婪的;会尽可能多的匹配内容

什么意思,举个例子:<html><head><title>Title</title> 我要提取这个字符串的所有Html标签

但要这样写 re.compile(r'<.*>').findall('<html><head><title>Title</title>')

结果是<html><head><title>Title</title> 它是<html><head><title>Title</title>匹配的最后一个>

改成非贪婪模式需要在*后面加?也就是 re.compile(r'<.*?>').findall('<html><head><title>Title</title>')

>>>['<html>', '<head>', '<title>', '</title>']

对元字符的转义

待搜索的文本:

苹果.是绿色的
橙子.是橙色的
香蕉.是黄色的

想要的内容:

苹果.
橙子.
香蕉.

这时如果正则表达式写成re.compile(r'.*.').findall(content)不对;因为.点是一个元字符,直接出现在正则表达式中,表示匹配任意的单个字符, 不能表示 . 这个字符本身的意思了,那就得加个\进行转义 re.compile(r'.*\.').findall(content)

匹配某种字符类型

\d:匹配0-9之间任意一个数字字符

\D:匹配任意一个非0-9数字的字符

\s:匹配任意一个空白字符,包括 空格、tab、换行符等

\S:匹配任意一个非空白字符

\w:匹配任意一个文字字符,包括大小写字母、数字、下划线

\W:匹配任意一个非文字字符

方括号

匹配指定的几个字符之一

例如:[abc] 匹配 a, b, 或者 c 里面的任意一个字符 ; <=> [a-c]

注意:一些元字符比如在[]中和普通字符一样;但^在[]表非的含义

起始、结尾位置和单行、多行模式

^ 表示匹配文本的开头位置

正则表达式通过compile的第二个参数re.M 来指明使用的是多行模式

单行模式:匹配 整个文本 的开头位置

多行模式:匹配 文本每行 的开头位置

例如:在下面文本内容提取编号 

content = '''001-苹果价格-60
002-橙子价格-70
003-香蕉价格-80'''

import re
p = re.compile(r'^\d+', re.M)
for one in  p.findall(content):
    print(one)

 r'^\d+' :匹配文本每行开头位置,0-9,匹配前面子表达式至少出现1次

去掉re.M的话是单行模式,^ 只会匹配整个文本的开头位置  >>> 001

$表示匹配文本的结尾位置

正则表达式通过compile 的第二个参数 re.MULTILINE ,指明了使用的是多行模式

单行模式:匹配 整个文本 的开头位置

多行模式:匹配 文本每行 的开头位置

例如:在下面文本内容提取价格

content = '''001-苹果价格-60
002-橙子价格-70
003-香蕉价格-80'''

import re
p = re.compile(r'\d+$', re.MULTILINE)
for one in  p.findall(content):
    print(one)

去掉 re.MULTILINE的话就是单行模式,$ 只会匹配整个文本的结束位置  >>>80

竖线

匹配其中之一

竖线在正则表达式的优先级最低

括号

例1

待搜索文本:

苹果,苹果是绿色的
橙子,橙子是橙色的
香蕉,香蕉是黄色的

想要的内容:

苹果
橙子
香蕉

content = '''苹果,苹果是绿色的
橙子,橙子是橙色的
香蕉,香蕉是黄色的'''

import re
p = re.compile(r'^(.*),', re.MULTILINE)
for one in  p.findall(content):
    print(one)

例2

待搜索文本:

张三,手机号码15945678901
李四,手机号码13945677701
王二,手机号码13845666901

content = '''张三,手机号码15945678901
李四,手机号码13945677701
王二,手机号码13845666901'''

import re
p = re.compile(r'^(.+),.+(\d{11})', re.MULTILINE)
for one in  p.findall(content):
    print(one)

>>>  ('张三', '15945678901')
        ('李四', '13945677701')
        ('王二', '13845666901') 

当有多个分组时,可以使用 (?P<分组名>...) 这样的格式,给每个分组命名,以便后续的代码提取每个分组里面的内容

content = '''张三,手机号码15945678901
李四,手机号码13945677701
王二,手机号码13845666901'''

import re
p = re.compile(r'^(?P<name>.+),.+(?P<phone>\d{11})', re.MULTILINE)
for match in  p.finditer(content):
    print(match.group('name'))
    print(match.group('phone'))

张三
15945678901
李四
13945677701
王二
13845666901

让点匹配换行

content = '''
<div class="el">
        <p class="t1">           
            <span>
                <a>Python开发工程师</a>
            </span>
        </p>
        <span class="t2">南京</span>
        <span class="t3">1.5-2万/月</span>
</div>
<div class="el">
        <p class="t1">
            <span>
                <a>java开发工程师</a>
            </span>
        </p>
        <span class="t2">苏州</span>
        <span class="t3">1.5-2/月</span>
</div>
'''

import re
p = re.compile(r'class="t1">.*?<a>(.*?)</a>', re.DOTALL)
for one in  p.findall(content):
    print(one)

正常情况下点是不匹配换行符的;要想匹配换行符需要在compile函数的第二个参数设成re.DOTALL 

正则表达式中的所有函数

search

扫描整个字符串,判断有无匹配的子串,如果匹配成功,将返回第一个匹配的字符串对象

import re

text = "Hello, world! How are you?"
pattern = "world"

match = re.search(pattern, text)
if match:
    print(match)
else:
    print("匹配失败")

 >>>  <re.Match object; span=(7, 12), match='world'>

match

用于判断字符串的起始位置是否与正则表达式匹配

它接受两个参数:第一个是正则表达式模式,第二个是要与该模式匹配的字符串。

如果匹配成功,它会返回一个匹配对象,如果匹配失败,则返回 None

import re

text = "Hello, world!"
pattern = re.compile("Hello")

match = pattern.match(text)
if match:
    print(match)
else:
    print("匹配失败")

>>> <re.Match object; span=(0, 5), match='Hello'>

findall

会找到所有的匹配结果,并且将所有的匹配结果组成一个列表进行返回

import re

text = "Hello, world! How are you? world"
pattern = "world"

match = re.findall(pattern, text)
if match:
    print(match)
else:
    print("匹配失败")

>>> ['world', 'world']

fullmatch

用于检查输入字符串是否完全匹配给定的正则表达式模式

它接受两个参数:第一个是正则表达式模式,第二个是要与该模式匹配的字符串。

如果匹配成功,它会返回一个匹配对象,如果匹配失败,则返回 None

import re

text = "Hello, world!"
pattern = re.compile("Hello, world!")

match = pattern.fullmatch(text)
if match:
    print(match)
else:
    print("整个字符串与模式不匹配。")

>>> <re.Match object; span=(0, 13), match='Hello, world!'> 

表示在[0-13)之间匹配到了字符串Hello, world!

span表示的是匹配上的字符串的开始位置与结束位置,match表示匹配上的内容 

finditer

寻找字符串中与正则表达式匹配的字符串片段的所有结果;与findall()函数不同的是,finditer()函数返回的是一个迭代器,并可以获取更多的信息,如匹配字符串的起始和终止位置。

import re

text = "Hello, world! How are you? world"
pattern = "world"

match = re.finditer(pattern, text)
if match:
    print(match)
else:
    print("匹配失败")

>>> <callable_iterator object at 0x000002CD5220F9A0>
 

print([i for i in match])

[<re.Match object; span=(7, 12), match='world'>, <re.Match object; span=(27, 32), match='world'>]

对比findall()

import re

text = "Hello, world! How are you? world"
pattern = "world"

match = re.findall(pattern, text)
if match:
    print(match)
else:
    print("匹配失败")

['world', 'world']

split

用于在字符串中按照指定的规则分割字符串

该函数接受两个参数:第一个是要分割的字符串,第二个是分割规则(正则表达式)

它返回一个字符串列表,每个字符串代表一个分割后的部分

import re
re_str = r'\d+'
str1 = 'qwer1tyui345osdfghj99876kl'
result = re.split(re_str,str1)
print(result)

>>> ['qwer', 'tyui', 'osdfghj', 'kl']

这里 r'\d+' 表示至少1个或多个数字

sub

用于在字符串中替换与指定正则表达式匹配的部分

该函数接受三个参数:第一个是替换规则(正则表达式),第二个是要替换的字符串,第三个是要被替换的字符串

它返回一个替换后的字符串

import re

re_str = r'\d+'
str1 = 'qwer1tyui345osdfghj99876kl'
str1 = re.sub(re_str, '一二三',str1) # 用'一二三'替换str1中所有匹配re_str的子串
print(str1)

 >>> qwer一二三tyui一二三osdfghj一二三kl

compile

正则表达式字符串编译成一个正则表达式对象

import re

re_pattern = re.compile(r'\d+')
str1 = 'qwer1tyui345osdfghj99876kl'
result1 = re_pattern.findall(str1)
result2 = re_pattern.search(str1)
print(result1)
print(result2)

>>>  ['1', '345', '99876']
        <re.Match object; span=(4, 5), match='1'>

切割字符串

import re

names = '关羽; 张飞, 赵云,   马超, 黄忠  李逵'

namelist = re.split(r'[;,\s]\s*', names)
print(namelist)

 r'[;,\s]\s*':代表从;,空格任选其一,并且该符号周围可以有不定数量的空格

字符串替换

匹配模式替换

import re

names = '''

下面是这学期要学习的课程:

<a href='https://www.bilibili.com/video/av66771949/?p=1' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是牛顿第2运动定律

<a href='https://www.bilibili.com/video/av46349552/?p=125' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是毕达哥拉斯公式

<a href='https://www.bilibili.com/video/av90571967/?p=33' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是切割磁力线
'''

newStr = re.sub(r'/av\d+/', '/cn345677/' , names)
print(newStr)

指定模式替换

要求:替换后的内容 是原来的数字+6, 比如 /av66771949/ 替换为 /av66771955/

import re

names = '''

下面是这学期要学习的课程:

<a href='https://www.bilibili.com/video/av66771949/?p=1' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是牛顿第2运动定律

<a href='https://www.bilibili.com/video/av46349552/?p=125' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是毕达哥拉斯公式

<a href='https://www.bilibili.com/video/av90571967/?p=33' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是切割磁力线
'''

# 替换函数,参数是 Match对象
def subFunc(match):
    print(match)
    print(match.group(0))
    print(match.group(1))
    print(match.groups())
    # Match对象 的 group(0) 返回的是整个匹配上的字符串, 
    src = match.group(0)

    # Match对象 的 group(1) 返回的是第一个group分组的内容
    number = int(match.group(1)) + 6
    dest = f'/av{number}/'

    print(f'{src} 替换为 {dest}')

    # 返回值就是最终替换的字符串
    return dest

newStr = re.sub(r'/av(\d+)/', subFunc , names)
print(newStr)

<re.Match object; span=(56, 68), match='/av66771949/'>
/av66771949/
66771949
('66771949',)
/av66771949/ 替换为 /av66771955/
<re.Match object; span=(168, 180), match='/av46349552/'>
/av46349552/
46349552
('46349552',)
/av46349552/ 替换为 /av46349558/
<re.Match object; span=(281, 293), match='/av90571967/'>
/av90571967/
90571967
('90571967',)
/av90571967/ 替换为 /av90571973/


下面是这学期要学习的课程:

<a href='https://www.bilibili.com/video/av66771955/?p=1' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是牛顿第2运动定律

<a href='https://www.bilibili.com/video/av46349558/?p=125' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是毕达哥拉斯公式

<a href='https://www.bilibili.com/video/av90571973/?p=33' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是切割磁力线

match.group() & match.groups()

首先在正则表达式中 ()定义了一个组;这里(\d+)是一组

match.group(0) :匹配的是整个结果

match.group(1):匹配的是第一个group值

这里是('66771949',)的66771949

注意:

为什么match.group(2)会报错 —— 当元组中只有一个元素,必须在它后面加逗号;这个元组只有一个group值

match.groups():返回所有的group,以元组的形式

参考自:python正则表达式中group_match.group()-CSDN博客  


原文地址:https://blog.csdn.net/m0_73557953/article/details/142922197

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!