python学习笔记(二十五) -- 正则表达式

版权声明:weixin_40247263的博客 https://blog.csdn.net/weixin_40247263/article/details/82350478

Table of Contents

re模块

精准匹配

更精准的匹配

正则表达式与split配合使用

分组

贪婪匹配


re模块

 python通过re模块来实现正则表达式与字符串的匹配。

re的match函数需要两个参数,参数一正则表达式、参数二被匹配的字符串。

如下:

>>> re.match('\d','12345')     # 匹配成功返回match对象,同时返回匹配到的字符
<re.Match object; span=(0, 1), match='1'>   # \d 代表匹配一个数字,匹配字符串的第一个字符
>>> re.match('\d','a12345')    # 匹配不成功返回None

match函数执行过程当中,分为两步:

1、编译正则表达式

2、与字符串匹配

所以如果一个正则表达式会被多次使用,我们可以预先编译好正则表达式,需要匹配的时候直接对比就好,就无需每次都调用match函数进行编译的重复操作了。

预先编译的方式如下:

>>> match_number = re.compile('\d')  # 预先编译好
>>> match_number.match('123')  # 匹配时这么调用
<re.Match object; span=(0, 1), match='1'>
>>> match_number.match('123') # 再次调用也不会再次编译
<re.Match object; span=(0, 1), match='1'>

还要注意一点,因为正则表达式很多字符匹配都是 以 \ 开头的,但是在python中 \ 代表转义字符,且python会优先使用字符转义,然后再使用正则表达式里面的转义。举个例子

#!/usr/bin/env python
# coding=utf-8
 
import re
 
string = '3\8'
m = re.search('(\d+)\\\\', string)
 
if m is not None:
    print m.group(1)  # 结果为:3
 
n = re.search(r'(\d+)\\', string)
 
if n is not None:
    print n.group(1)  # 结果为:3

1)'\\\\'的过程:
先进行“字符串转义”,前两个反斜杠和后两个反斜杠分别被转义成了一个反斜杠;即“\\|\\”被转成了“\|\”(“|”为方便看清,请自动忽略)。“字符串转义”后马上进行“正则转义”,“\\”被转义为了“\”,表示该正则式需要匹配一个反斜杠。

2)r'\\'的过程:
由于原始字符串中所有字符直接按照字面意思来使用,不转义特殊字符,故不做“字符串转义”,直接进入第二步“正则转义”,在正则转义中“\\”被转义为了“\”,表示该正则式需要匹配一个反斜杠。 

所以我们在 字符串前 加上 r来 取消字符转义,来保证不会出现问题 如下:

>>> re.match(r'^\d{3}\-\d{3,8}$', '010-12345')
<_sre.SRE_Match object; span=(0, 9), match='010-12345'>

上面的 \-  代表匹配 -  ,但这个不是因为 \ 是转义字符,而是因为在正则表达式中  \- 就代表匹配 - 。

精准匹配

字符含义

\d    匹配一个数字
\w    匹配一个数字或一个字母
\s    匹配一个空格
.     匹配任意一个字符
*     匹配任意字符且任意个数,如 \s* 匹配任意多个空格包括0
+     匹配0或1个任意字符,如 \d+ 匹配0或1个数字
{n}   表示n个字符
{n,m} 表示n-m个字符

例子:

\d{3}\s+\d{3,8}

我们来从左到右解读一下:

\d{3}表示匹配3个数字,例如'010';

\s可以匹配一个空格(也包括Tab等空白符),所以\s+表示至少有一个空格,例如匹配' ',' '等;

\d{3,8}表示3-8个数字,例如'1234567'。

更精准的匹配

[]    表示范围


例一:
      [0-9a-zA-Z\_]  

与字符串的第一个字符进行匹配,判断其第一个字符是否是 数字 或 字母(大小写均可) 或 下划线


例二:
      [0-9a-zA-Z\_]+

从字符串的第一个字符开始进行匹配,直到遇到的字符非数字、字母、下划线为止。
说白了只要第一个字符是数字 或字母或下划线就匹配成功。


例三:
      [a-zA-Z\_][0-9a-zA-Z\_]*

可以匹配由字母或下划线开头,后接任意个由一个数字或字母或者下划线组成的字符串。


例四:    
      [a-zA-Z\_][0-9a-zA-Z\_]{0, 19}

更精确地限制了变量的长度是1-20个字符(前面1个字符+后面最多19个字符)。
^    后面的正则表达式符号用来匹配字符串的第一个字符
$    前面的正则表达式符号用来匹配字符串的最后一个字符


例:  r'^\d{3}\-\d{3,8}$'
    
      代表 前三个字符为数字 加上一个 - 再加上 3~8个数字

正则表达式与split配合使用

# 我们想根据空格将 一个字符串 切分成 字符数组

>>> 'a b  c'.split(' ')   # ab之间一个空格,bc之间两个空格,小括号里一个空格。
['a', 'b', '', 'c']  # 结果发现由于 空格个数 不一样,无法真正做到按到空格来划分字符串

我们将正则表达式与split相结合

# 使用re模块的split函数
>>> re.split(r'\s+','a b   c')  # 第一个参数 r'\s+'  用来匹配 1个或多个空格
['a', 'b', 'c'] 

无论多少个空格都可以正常分割。加入,试试:

>>> re.split(r'[\s\,]+', 'a,b, c  d')
['a', 'b', 'c', 'd']

再加入;试试:

>>> re.split(r'[\s\,\;]+', 'a,b;; c  d')
['a', 'b', 'c', 'd']

分组

re.split 函数可以将一个字符串 根据正则表达式匹配到的字符 分为多个字符串 从而放入一个 list 中

re.match().groups() 函数可以将 根据正则表达式匹配 提取出某些 从而放入一个 tuple 中

()表示的就是要提取的分组(Group)。比如:

^(\d{3})-(\d{3,8})$分别定义了两个组,可以直接从匹配的字符串中提取出区号和本地号码:

>>> re.match(r'^(\d{3})-(\d{3,8})$', '010-12345').groups() # 首先用正则表达式与字符串匹配,如果匹配成功,将与小括号括起来的部分对应的字符串提取出来放入tuple中
('010', '12345')
>>> m = re.match(r'^(\d{3})-(\d{3,8})$', '010-12345') 
>>> m
<_sre.SRE_Match object; span=(0, 9), match='010-12345'>
>>> m.group(0)    # 也可以通过这种方式来获取,0 返回的是完整的字符串
'010-12345' 
>>> m.group(1)    # 1 代表 tuple中的第一个元素,往后类推
'010'
>>> m.group(2)
'12345'

贪婪匹配

最后需要特别指出的是,正则匹配默认是贪婪匹配,也就是匹配尽可能多的字符。举例如下,匹配出数字后面的0

>>> re.match(r'^(\d+)(0*)$', '102300').groups() 
('102300', '')

# 分析: 
#    ^(\d+) 匹配以数字开头同时向后匹配多个数字
#    (0*)$  匹配以0结尾的字符串  
#    小括号代表提取出 末尾最后几个0 ,以及其前半部分的数字
#    但结果显然不是我们想要的

# 原因:
#     (\d+) 采取了贪婪匹配,其从第一个数字一直匹配到了最后一个
#     所以 (0*) 只有在 正则匹配的时候发挥了作用,而实际调用groups函数时并没有提取出字符

必须让\d+采用非贪婪匹配(也就是尽可能少匹配),才能把后面的0匹配出来,加个?就可以让\d+采用非贪婪匹配:

>>> re.match(r'^(\d+?)(0*)$', '102300').groups()
('1023', '00')

猜你喜欢

转载自blog.csdn.net/weixin_40247263/article/details/82350478