正则表达式详解

1、简介

正则表达式(Regular expressions 也称为 REs,或 regexes 或 regex patterns)本质上是一个微小的且高度专业化的编程语言。这个概念最初是由 Unix 中的工具软件(例如 sed 和grep)普及开的。

正则表达式是对 字符串操作 的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。给定一个正则表达式和另一个字符串,可以通过正则表达式从字符串中获取我们想要的特定部分。正则表达式灵活性、逻辑性和功能性非常强,可以迅速地用极简单的方式达到字符串额复杂控制,但对于共接触的人来说比较晦涩难懂。由于 正则表达式主要应用对象是文本,因此他在各种文本编辑器场合都有应用。

Python 的正则表达式引擎是用 C 语言写的,所以效率是极高的。可以帮我们处理 98.3% 的文本任务。

1.1 处理字符串主要有四大功能

  • 匹配 查看一个字符串是否符合正则表达式的语法,一般返回 true 或者 false

  • 获取 正则表达式来提取字符串中符合要求的文本

  • 替换 查找字符串中符合正则表达式的文本,并用相应的字符串替换

  • 分割 使用正则表达式对字符串进行分割。

2、字符匹配与获取

2.1 简单使用

2.1.1 导入库

import re

2.1.2 方法使用

pattern:匹配的正则表达式

string:要匹配的字符串

flags:标志位,用于控制正则表达式的匹配方式

  1. re.match(pattern,string,flags)

    返回 string 中所有与 pattern 相匹配的 第一个 字符串的 Match 对象,如果字符串没有匹配,则返回 None。

    re.match函数只匹配字符串的开始字符。

    返回值函数

    match() 方法一旦匹配成功,就是一个 match object 对象,而 match object 对象有以下方法:

    • group() 返回被 RE 匹配的字符串,默认 group(0)
    • start() 返回匹配开始的位置
    • end() 返回匹配结束的位置
    • span()返回一个元组包含匹配 (开始, 结束) 的位置
  2. re.search(pattern, string, flags)

    返回 string 中所有与 pattern 相匹配的 第一个 字符串的 Match 对象,如果字符串没有匹配,则返回 None。

    re.search()方法匹配整个字符串,直到找到一个匹配的对象。

  3. re.findall(pattern, string, flags)

    返回 string 中所有与 pattern 相匹配的 全部字符串 对象,返回形式为数组.。

  4. re.finditer(pattern, string, flags)

    返回 string 中所有与 pattern 相匹配的 全部字串 对象,返回形式为迭代器。

  5. re.compile(pattern, flags)

    函数根据一个模式字符串和可选的标志参数返回一个正则表达式对象。

为什么要有 re.compile ?

该函数根据包含的正则表达式的字符串创建模式对象。可以实现更有效率的匹配。

在直接使用字符串表示的正则表达式进行 search, match 和 findall 操作时,python 会将字符串转换为正则表达式对象。而使用 compile 完成一次转换之后,在每次使用模式的时候就不用重复转换。

2.1 字符匹配模式

正则表达式 pattern 有两种匹配模式:

直接匹配:如正则表达式FishC 将完全匹配字符串 "FishC",给啥匹配啥,明面上的直接匹配。

元字符匹配:正则表达式中定义了一类特殊字符,约定俗成的表达特定含义,进行匹配搜索。

2.1.1 直接匹配

import re
r=re.findall('Mi','Mike is Mifan,is him? ')
print(r)

rs=re.search('Mi','Mike is Mifan,is him? ')
print(rs)
print(rs.group())

// 输出结果如下
['Mi', 'Mi']

<re.Match object; span=(0, 2), match='Mi'>
Mi

2.1.2 元字符匹配

首先一定要记住以下元字符及其代表的含义:

贪婪匹配:正则表达式一般趋向于最大长度匹配,默认形式。

非贪婪模式:在满足匹配时,匹配尽可能短的字符串。匹配到一块字符(可以为空),再去匹配下一处。

还有反斜杠带来的扩展:

2.1.3 标志位

还有标志位 flags,用于控制正则表达式的匹配方式:

2.1.4 举例

import re
str='Mike is Mifan,his age is 180 years old,and his weight is about 140 pound.'

r=re.findall('his age is (\d+)',str)
print(r)
// 输出结果如下
['180']

r=re.findall('his age is \d+',str)  // 与上对比,可说明 () 的作用
print(r)
// 输出结果如下
['his age is 180']

r=re.findall('his age is (\d+?)',str)    // 问号前的 \d+ 由于问号,整体变成非贪婪模式
print(r)
// 输出结果如下
['1']

r=re.findall('his age is (.+)',str)  //. 会匹配任何值,再加上 +,则会贪婪匹配后面所有内容
print(r)
// 输出结果如下
['180 years old,and his weight is about 140 pound.']

r=re.findall('\d+',str)
print(r)
// 输出结果如下
['180', '140']

r=re.findall('\d',str)
print(r)
// 输出结果如下
['1', '8', '0', '1', '4', '0']

r=re.findall('is about (.*[.]$)',str)   //[]里填其他字符无效,会取出空值
print(r)
// 输出结果如下
['140 pound.']

rs = re.search('is about (.*[.]$)',str)
print(rs)
print(rs.group())
print(rs.group(1))
// 输出结果如下
<re.Match object; span=(54, 73), match='is about 140 pound.'>
is about 140 pound.
140 pound.

r=re.findall('his (.*)',str)
print(r)
rs=re.findall('his (.*) years',str)   // 这里的 '[空格]years' 有拦截效果
print(rs)
ra=re.findall('his (.*?) years',str)  
print(ra)
// 输出结果如下
['age is 180 years old,and his weight is about 140 pound.']
['age is 180']
['age is 180']
// 上面第三个匹配多一个问号的区别在于是非贪婪模式,匹配到一个 'his (.*?) years' 就停止匹配;
// 贪婪模式会输出所有符合 'his (.*) years' 的结果

r=re.findall('his (.*?) ',str)  // 注意括号后有空格,若去掉空格,则返回为空
print(r)
// 输出结果如下
['age', 'weight']

小心空格,一不小心就成了拦截符!,对非贪婪匹配结果有大影响。

3、字符替换与分割

3.1 方法使用

首先将正则表达式的字符串创建成模式对象,再来使用:

rx = re.compile(pattern, flags)

  1. rx.split(string,maxsplit)

    在正则表达式匹配的地方进行分割,并返回一个列表。

  2. rx.sub(replacement, string, count)

    返回替换后的字符串,这个字符串从最左边开始,所有 RE 匹配的地方都替换成 replacement

  3. rx.subn(replacement, string, count)

    返回值为一个包含有两个元素的元组:替换后的字符串,替换的数目

4、常用的正则表达式

邮箱地址(Email)

pattern = r"([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)"

域名(domain)

pattern = r"http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+"

IP 地址

pattern = r"((?:(?:25[0-5]|2[0-4]\d|(?:1\d{2}|[1-9]?\d))\.){3}(?:25[0-5]|2[0-4]\d|(?:1\d{2}|[1-9]?\d)))"

电话号码

pattern = r"\d{3,4}-\d{7,8}"

手机号码

pattern = r"(?:13[0-9]|15[0-9]|17[0678]|18[0-9]|14[57]|09){1}[0-9]{8}"

身份证号码(18 位)

pattern = r"(?:[1-9]\d{5}[12]\d{3}(?:0[1-9]|1[012])(?:0[1-9]|[12][0-9]|3[01])\d{3}[0-9xX])"

中文字符

pattern = r"[\u4e00-\u9fa5]"

欢迎各位看官及技术大佬前来交流指导呀,可以邮件至 jqiange@yeah.net