Python学习笔记 十四 (正则表达式)

正则表达式在处理文本和数据时有着重要的作用,通过对正则表达式的学习后在这里进行一个总结记录,希望能对你我有益。

一、第一个正则表达式

#正则表达式
import re	#导入re(正则表达式的包)
message = "hello world!"
r = "\w?"	#正则表达式 意思为匹配一个字母或字符并且只匹配一次
m = re.search(r,message) #re库中的search函数用于搜索一次,未搜索到会返回None
if m is not None:
    print(m.group())	#输出匹配结果
-----------------------------------------------------
==
h
>>> 

二、正则表达式使用的特殊字符的介绍

在上面我所使用的正则表达式就是利用正则表达式中的特殊字符来代替所要搜索的文本内容,当然正则表达式中特殊字符肯定不止这一种,下面我就来一一介绍正则表达式中的特殊字符及其其中的含义和功能(在例子中所使用的函数在后面会进行介绍)。

1. 管道符 |

用来匹配多个表达式内容相当于“或”的意思。

例:

import re
message = "hello world!"
r = "e|!"
m = re.search(r,message)
if m is not None:
    print(m.group())
---------------------------
==
e
>>> 

上述例子功能是从字符串“hello world!”中搜索出e或者!且只搜索一次,程序在第二个单词中搜素到了e成功并返回e。

2. 点字符 .

点字符用于匹配任意一个除换行符外的单字符。

例:

import re
message = "hello world!"
r = ".!"
m = re.search(r,message)
if m is not None:
    print(m.group())
----------------------------
==
d!
>>> 

上述例子中的表达式表示搜索一个!前面有一个任意字符的结果,因此点字符可以理解为表示所搜索对象中的任意一个字符(比如可以使用 . . 表示搜索任意两个字符)。

常用方法比如:
. . —— 表示搜索任意两个字符
f.o —— 表示搜索 f 和 o 之间的字符,比如fao、f3o等

3. ^ / $ 以及 \b / \B 符

^、$、\b、\B这些符号都是用于边界搜索即从字符串或者字符的边界开始匹配合适的字符。

其中 ^ 表示搜索以该符号右边字符开始的字符串;$表示搜索该符号左边字符结束的字符串。

^hello —— 表示匹配任何以hello开始的字符串

hello$ —— 表示匹配任何以hello结尾的字符串

^hello$ —— 表示匹配仅由hello组成的字符串(以hello开头和结尾即hello本身)

\b hello —— 表示匹配任何以以“hello”开头的字符串(无论字符串在源数据的那个位置)

\b hello \b —— 来仅匹配hello这个单词

\B hello—— 表示匹配任意包含“hello”但不以hello开头的字符串(无论字符串在源数据的那个位置)

例:

import re
message = "hello world!"
r = "^h"	
m = re.search(r,message)
if m is not None:
    print(m.group())
---------------------------
==
h
>>> 
import re
message = "hello world!"
r = "^e"
m = re.search(r,message)
if m is not None:
    print(m.group())
--------------------
未匹配到

上述例子说明了^是表示匹配以h字符开始的字符串,即将该字符仅仅和源数据第一个字符进行匹配,不成功则返回None,而不是在按顺序在字符串中进行匹配知道成功为止。

import re
message = "hello world!"
r = "!$"
m = re.search(r,message)
if m is not None:
    print(m.group())
-----------------------
==
!
>>> 

$的使用和^相反,匹配以该字符结尾的字符串。

import re
message = "hello world!"
r = r"\bw"
m = re.search(r,message)
if m is not None:
    print(m.group())
--------------------------
==
w
>>> 
import re
message = "hello world!"
r = r"\Brl"
m = re.search(r,message)
if m is not None:
    print(m.group())
---------------------------
==
rl
>>> 

和 ^ / $ 不同的是 \b 和 \B可以理解为是以单词为单位,前者是以字符串为单位,即\b和\B不考虑所要匹配的对象的位置是否在一个字符串的开头或者结尾(该词可以在一个字符串的中间)。

其中在使用\b和\B时使用的 r ——原始字符串在后面会介绍到。

4.[ ] 字符类

我们在需要匹配多个字符时使用多个管道符号会显得有些臃肿,而 [ ] 可以解决这个问题将多个字符包含在一起。

其使用方法比如:
[abc] —— 表示匹配含有a或者b或者c的字符串。
b[aie]t —— 表示匹配bat、bit、bet字符串。

在使用多个[ ][ ]进行匹配时要注意和管道符号的区分,管道符是将管道符两边看做整体,而大括号是将括号内的每一个单字符看做一个整体来分别进行匹配。

5.指定范围 - 以及否定 ^

在匹配有规律的一串字符时如果单个匹配会显得很麻烦,于是我们可以使用 - 符号进行匹配范围指定。
例如:
[a-z] —— 表示匹配从小写 a 到小写 z 之间的字母。
[A-Z] —— 表示匹配从大写 a 到大写 z 之间的字母。
[0-9] —— 表示匹配从数字0到数字9之间的数字。
如果在字符集中的左边第一个字符前添加 ^ 就表示匹配除字符集里面的字符。
例如:
[^abc] —— 表示匹配除abc之外的字符。

import re
message = "hello world!"
r = "[m-z]"
m = re.search(r,message)
if m is not None:
    print(m.group())
--------------------------------
==
o
>>> 
6.闭包操作符(*,+,?,{ })重复匹配
  • 闭包操作符 * :表示将 *左边的字符匹配 0 到多次。
  • 闭包操作符 +:表示将 +左边的字符匹配1次至多次(最少一次的意思)。
  • 闭包操作符 ?:表示将?左边的字符匹配0或1次(最多一次的意思)。
  • 闭包操作{m, n }:表示将左边的字符匹配m次或n次。

例如:
boys?:表示boy后面最多在有一个s字符。
[0-9]{11,12}:表示匹配11或者12位数字组成的字符串。

import re
message = "abc123456789101112"
r = "[0-9]{11,12}"
m = re.search(r,message)
if m is not None:
    print(m.group())
-------------------------
==
123456789101
>>> 

7.特殊字符表示、字符集

特殊字符表示是对范围指定的简化,例如可以使用

  • \d 表示0-9的数字即相当于[0-9]。
  • \D 表示非数字的字符集即相当于[^0-9]
  • \w 可以表示字符和数字的字符集。
  • \s 表示空白字符。

常用操作:
\w + \w + \.com —— 表示匹配 xxx@yyy.com的电子邮件格式。

import re
message = "1111111@qq.com"
r = "\w+@\w+\.com"
m = re.search(r,message)
if m is not None:
    print(m.group())
----------------------------
==
1111111@qq.com
>>> 

\ . 的作用是将点符号转义,因为这里是需要匹配文本 . 的。

8.使用 ( ) 建组

有时候在对匹配的数据进行处理时可能会需要获取某个匹配成功的特定字符这时候我们就需要使用建组来控制,当然我们也可以写一个函数来实现,但是通过建组显得更为方便。
其使用方法是在每个子组加上()这样在后期对这个子组进行处理就会很方便。

例如:
(\d\d\d\d) - (\d\d):用来匹配年-月格式的日期,通过建组我们可以在进行处理的时候使用group(1)来获取子组1年的日期。

关于group函数在后面会进行介绍。

三、Python中关于正则表达式的一些函数

在python中使用这些函数需要导入re包,import re 即可;下述解释中pattern为正则的式子,string为所要匹配的字符串。

  1. re.match(pattern,string):尝试从字符串开头进行模式匹配,匹配成功返回一个匹配对象,若匹配不成功则返回None。
  2. re.search(pattern,string):会从字符串任意的地方对正则进行匹配,匹配成功返回一个匹配对象,若匹配不成功则返回None。
import re
message = "cdab"
r = "ab"
m = re.match(r,message)
if m is not None:
    print(m.group())
--------------------
未匹配到
import re
message = "cdab"
r = "ab"
m = re.search(r,message)
if m is not None:
    print(m.group())
------------------------
==
ab
>>> 

注意:match函数和search函数之间的区别可以理解为match是从字符串开头进行严格匹配,而search函数可以理解为是从字符串开头按顺序从左到右依次搜索。
例如:
re.match(‘ab’, ‘cdab’)将会匹配不到因为match函数是将ab与字符串的开始cd进行匹配因此无法匹配成功;而re.search(‘ab’, ‘cdab’)将会匹配成功,因为ab在字符串中。

  1. findall(pattern,string):和match函数和search函数不同的是,findall函数总是会返回一个列表,列表中列出来所匹配到的元素(按照匹配的先后顺序进行排列),若没有匹配到则返回空列表。
import re
message = "eqccccababccccab"
r = "ab"
m = re.findall(r,message)
if m is not None:
    print(m)
-----------------------
==
['ab', 'ab', 'ab']
>>> 
  1. split(pattern,string):和前面的字符串处理类似,相比前面的对于固定字符的分割,这里的split函数是根据正则表达式进行匹配后分割(将正则当做分割条件),因此更为灵活;例如在Windows系统下使用dir命令得到如下目录信息,我们在使用这些数据是希望中间没有空格或者tab符,这时候使用正则来分割显得很简单了。
    在这里插入图片描述
import re
f = open("D:/pythonProgram/dir.txt",encoding='utf-8')
r = "\s\s+|\t"
for line in f.readlines():
    print(re.split(r,line))
f.close()

在这里插入图片描述
5. sub(pattern, rep, string):作用是将正则所匹配的元素替换为rep。

import re
mes = "12bcd6789"
r = "\d"
print(re.sub(r,'a',mes),end='')
-----------------------------------
aabcdaaaa
>>> 

subn函数和sub函数相同不过在返回时会带上替换的次数。

import re
mes = "12bcd6789"
r = "\d"
print(re.subn(r,'a',mes),end='')
----------------------------------
('aabcdaaaa', 6)
>>> 
  1. group(num):是用来返回所匹配的对象,返回的内容包含唯一或所有子组,其中的参数num是用于在建组后返回某一个特定匹配内容。
import re
mes = "12bcd6789"
r = "(\d)([a-z])"
m = re.search(r,mes)
print(m.group(1),end='')
------------------------
2
>>> 
import re
mes = "12bcd6789"
r = "(\d)([a-z])"
m = re.search(r,mes)
print(m.group(2),end='')
b
>>> 
  1. groups():返回所有匹配的子组的元组。
import re
mes = "12bcd6789"
r = "(\d)([a-z])"
m = re.search(r,mes)
print(m.groups(),end='')
---------------------------
('2', 'b')
>>> 

四、实例 - (处理一段文本并输出为表格形式)

1.问题分析

在这里插入图片描述
本实例是通过正则表达式来分离表中的某个元素并输出为表格形式。

  • 首先我们确定需要分离的元素为:邮箱、电话、得分、奖金。

  • 对需要分离的元素制定对应的正则表达式。
    邮箱,通过观察我发现邮箱主要是有一串数字加@符加一串字母以及跟上.com组成,因此我所制定的正则表达式为:\w+@\w+.com。
    电话是由11位数字组成,因此对应的正则表达式为:\d{11}。
    得分仅仅是由两位数字组成因此对于的正则表达式为:\b\d{2}\b。
    奖金仅仅是由一位数字后面接上2到3个0,因此对应的正则表达式为:\b\d0{2,3}\b。

  • 编写代码并输出为表格形式(这里使用的是csv模块)。

2.编写代码
import re
import csv
f = open("D:/pythonProgram/project_csdn/information.txt","rt", encoding='utf-8')

emailText = open("email.csv", "w", newline = "")
telText = open("tel.csv", "w", newline = "")
scodeText = open("scode.csv", "w", newline = "")
moneyText = open("money.csv", "w", newline = "")

emWriter = csv.writer(emailText)	#创建一个csv对象
teWriter = csv.writer(telText)
scWriter = csv.writer(scodeText)
moWriter = csv.writer(moneyText)

emWriter.writerow(["电子邮件"])	#写表头
teWriter.writerow(["电话"])
scWriter.writerow(["得分"])
moWriter.writerow(["奖金"])

email = "\w+@\w+\.com"	#正则表达式
tel = r"\d{11}"
scode = r"\b\d{2}\b"
money = r"\b\d0{2,3}\b"

for line in f.readlines():
    em = re.search(email,line)
    if em is not None:
       emWriter.writerow([em.group()])	#写入内容
    te = re.search(tel,line)
    if te is not None:
        teWriter.writerow([te.group()])
    sc = re.search(scode,line)
    if sc is not None:
        scWriter.writerow([sc.group()])
    mo = re.search(money,line)
    if mo is not None:
        moWriter.writerow([mo.group()])
    


3.实验结果

在这里插入图片描述

五、个人总结

  1. 在导出表格时,注意不能使用IDLE个人觉得是由于IDLE会对一些功能进行屏蔽和IDLE会屏蔽 \r (让光标回到行首)类似,建议使用集成开发环境或者使用命令行直接运行。
  2. 在使用正则表达式时要注意正则表达式默认的贪婪匹配性质,即正则表达式在进行从左到右进行匹配时会尽量“抓取”多的满足匹配条件的数据,使用“非贪婪”符?可以解决这个问题(“非贪婪”符?放在“ * ”、“+”、“?”的后面)会使正则表达式匹配的字符越少越好。
    例如:
import re
mes = "niahoshijie:1234567-8-9"
z = ".+(\d+-\d+-\d)"
m = re.search(z,mes)
if m is not None:
    print(m.group(1))
-----------------------------
==
7-8-9
>>> 

我们知道 .+ 表示匹配任意多个字符,而 \d+ -\d+ -\d 表示匹配0到多个数字 - 0到多个数字 - 0到多个数字;由于贪婪匹配的性质且 \d+ -\d+ -\d 最少7-8-9就可以完成匹配,因此==.+== 会尽可能多的“抓取”能匹配的元素即(niahoshijie:123456)。

import re
mes = "niahoshijie:1234567-8-9"
z = ".+?(\d+-\d+-\d)"
m = re.search(z,mes)
if m is not None:
    print(m.group(1))
---------------------------
==
1234567-8-9
>>> 

当我们不需要贪婪匹配时可以在其后面添加 “非贪婪”符 ?,就可以解决这个问题。

  1. 对正则表达式进行分组可以将对匹配的元素的操作变得简单。

  2. 在使用特殊符号的正则表达式时要注意原始字符的使用。
    原始字符是为了对付字符串的一些特殊符号;我们经常使用特殊字符的本来含义而使用转义符,为了防止使用多个转义符带来的混乱,通过在第一个引号前面添加R或者r来告诉介解释器这里的字符为书面意思,例如添加了原始字符标识的换行符\n就不再标识换行。

>>> print(r"\n")
\n
>>> 
import re
mes = "boy"
z = "\bboy"
m = re.search(z,mes)
if m is not None:
    print(m.group())
----------------------
未匹配到
-----------------------
import re
mes = "boy"
z = r"\bboy"
m = re.search(z,mes)
if m is not None:
    print(m.group())
----------------
==
boy
>>> 

上述例子是由于\b是一个退格符,而不是正则表达式中的\b(从头开始匹配),这里你可能有疑问为什么/d(匹配数字)不需要转义,这是因为在ASCII表中没有对于的特殊字符,因此正则编译器会将/d解释为一个十进制数字从而正确的进行匹配。

end…

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值